新聞中心
在前一篇我們了解了 Spring IOC, Spring AOP 的強(qiáng)大,以及對(duì)我們編程范式,編程基礎(chǔ)的影響。接下來(lái)我們一起來(lái)聊一下 Spring 基礎(chǔ)概念。對(duì)于基礎(chǔ)概念而言基本上都是屬于那種字典類型的會(huì)有一定的枯燥程度,大佬文末見(jiàn)。

霞山網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁(yè)設(shè)計(jì)、網(wǎng)站建設(shè)、微信開(kāi)發(fā)、APP開(kāi)發(fā)、響應(yīng)式網(wǎng)站建設(shè)等網(wǎng)站項(xiàng)目制作,到程序開(kāi)發(fā),運(yùn)營(yíng)維護(hù)。創(chuàng)新互聯(lián)從2013年成立到現(xiàn)在10年的時(shí)間,我們擁有了豐富的建站經(jīng)驗(yàn)和運(yùn)維經(jīng)驗(yàn),來(lái)保證我們的工作的順利進(jìn)行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
BeanDefinition Bean 定義信息
BeanDefinition 表示 Bean 的定義, BeanDefinition 中存在很多屬性來(lái)描述 Bean 的特征。比如:
- class, 表示 bean 的類型
- scope, 表示 bean 的作用域,單例(_singleton_)或者原型(_prototype_)
- lazyInit, 表示 bean 是否懶加載
- initMethodName, 表示 bean 的初始化需要執(zhí)行的方法
- destoryMethodName, 表示 bean 銷毀時(shí)需要執(zhí)行 bean 的方法
- and more ...
他的 Bean 屬性方法關(guān)系圖如下:
在 Spring 中,我們可以通過(guò)一下幾種方式來(lái)定義 bean 1、xml 方式,可以通過(guò) 標(biāo)簽定義一個(gè) bean 2、注解方式,可以通過(guò) @Bean、@Component(@Service, @Controller,@Repository) 這幾種方式,我們稱為 申明式定義 Bean
我們還可以通過(guò)編程式定義 bean, 比如直接通過(guò) BeanDefinition 創(chuàng)建, 比如:
public class BeanDefinitionTest {
public static void main(String[] args){
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext();
//定義 BeanDefinition
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
//設(shè)置 scope
beanDefinition.setScope(BeanDefinition.SCOPE_SINGLETON);
//設(shè)置bean類型
beanDefinition.setBeanClass(OrderService.class);
//設(shè)置懶加載
beanDefinition.setLazyInit(true);
//注冊(cè) bean
applicationContext.registerBeanDefinition("orderService", beanDefinition);
applicationContext.refresh();
System.out.println(applicationContext.getBean("orderService"));
}
}
class OrderService {
}
類比申明式事務(wù),編程式事務(wù),通過(guò) 、@Bean 、@Component 等申明方式所定義的 Bean , 最終都會(huì)被 Spring 解析為對(duì)應(yīng)的 BeanDefinition 對(duì)象,并且放入 Spring 容器中。
BeanDefinitionReader Bean定義讀取器
BeanDefinitionReader 是 Spring 容器中提供的 BeanDefinition 讀取器,用于將 Spring 的配置信息,轉(zhuǎn)換為 BeanDefinition 。提供了4個(gè)實(shí)現(xiàn)類:
- AbstractBeanDefinitionReader:是一個(gè)抽象類,同時(shí)實(shí)現(xiàn)了 EnvironmentCapable 接口,提供環(huán)境的get和set方法。它實(shí)現(xiàn)了BeanDefinitionReader 的一些通用方法,比如按照路徑來(lái)讀取 Bean 定義信息的方法→int loadBeanDefinitions(String location)。對(duì)于更為具體的方法,比如根據(jù)資源來(lái)讀取 Bean 定義信息的方法→int loadBeanDefinitions(Resource resource), 則交由子類來(lái)實(shí)現(xiàn)。
- PropertiesBeanDefinitionReader:是一個(gè)具體實(shí)現(xiàn)類,可以從properties文件讀取Bean定義信息。
- XmlBeanDefinitionReader:具體實(shí)現(xiàn)類,可以從XML文件讀取Bean定義信息。
- GroovyBeanDefinitionReader:具體實(shí)現(xiàn)類,可以讀取Groovy 語(yǔ)言寫的Bean的定義信息。
這些 BeanDefinitionReader 在我們使用 Spring 開(kāi)的時(shí)候較少使用,在 Spring 源碼中使用的比較多,相當(dāng)于是 Spring 內(nèi)部的基礎(chǔ)設(shè)施。
AnnotatedBeanDefinitionReader
可以直接把類轉(zhuǎn)換為 BeanDefinition , 并且會(huì)解析類上的注解,例如:
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(AnnotatedBeanDefinitionReaderTest.class);
AnnotatedBeanDefinitionReader annotationBeanDefinitionReader =
new AnnotatedBeanDefinitionReader(applicationContext);
annotationBeanDefinitionReader.register(UserService.class);
System.out.println(applicationContext.getBean(UserService.class));
XmlBeanDefinitionReader
XmlBeanDefinitionReader 可以讀取 xml 中 spring 的配置信息獲取 Bean 配置信息
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(XmlBeanDefinitionReaderTest.class);
XmlBeanDefinitionReader xmlBeanDefinitionReader =
new XmlBeanDefinitionReader(applicationContext);
xmlBeanDefinitionReader.loadBeanDefinitions("classpath:spring-context.xml");
System.out.println(applicationContext.getBean(UserService.class));
ClassPathBeanDefinitionScanner
ClassPathBeanDefinitionScanner 是掃描器,但是它的作用和 BeanDefinitionReader 類似,它可以進(jìn)行掃描,掃描某個(gè)包路徑,對(duì)掃描到的類進(jìn)行解析,比如,掃描到的類上如果存在 @Component 注解,那么就會(huì)把這個(gè)類解析為一個(gè) BeanDefinition ,比如:
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext(ClassPathBeanDefinitionScannerTest.class);
ClassPathBeanDefinitionScanner classPathBeanDefinitionScanner =
new ClassPathBeanDefinitionScanner(applicationContext);
classPathBeanDefinitionScanner.scan("com.summer.test.service");
System.out.println(applicationContext.getBean(UserService.class));
BeanFactory Bean工廠
BeanFactory 表示 Bean 工廠,負(fù)責(zé)創(chuàng)建 Bean,提供獲取 Bean 的 API。SpringApplicationContext 是 BeanFactory 的子類,通過(guò)ListableBeanFactory 繼承了 BeanFactory 接口,還實(shí)現(xiàn)了 EnvironmentCapable 、MessageSource 、ResourcePatternResolver 。在 Spring 的源碼中是這樣定義的:
public interface ApplicationContext extends EnvironmentCapable, ListableBeanFactory, HierarchicalBeanFactory,
MessageSource, ApplicationEventPublisher, ResourcePatternResolver {
// ...
}
ApplicationContext 繼承了 ListableBeanFactory 和 HierarchicalBeanFactory , 而 ListableBeanFactory 和 HierarchicalBeanFactory 都繼承自 BeanFactory , 所以我們可以認(rèn)為 ApplicationContext 繼承了 BeanFactory, ApplicationContext 也是 BeanFactory 的子類,擁有 BeanFactory 支持的所有功能。
ApplicationContext 比 BeanFactory 更加強(qiáng)大, ApplicationContext 還實(shí)現(xiàn)了其他的基礎(chǔ)接口。比如:MessageSource 國(guó)際化, ApplicationEventPublisher 事件發(fā)布, EnvironmentCapable 獲取環(huán)境變量等等,關(guān)于 ApplicationContext 后面詳細(xì)展開(kāi)。
在 Spring 源碼的實(shí)現(xiàn)中,當(dāng)我們創(chuàng)建一個(gè) ApplicationContext 時(shí),也是創(chuàng)建 BeanFactory 的一個(gè)實(shí)例, 相當(dāng)于使用了 ApplicationContext 的某些方法時(shí),比如 getBean() , 也是就是調(diào)用的 BeanFactory 的 getBean()。
在 Spring 源碼中, BeanFactory 接口存在一個(gè)非常重要的實(shí)現(xiàn)類:DefaultLIsttableBeanFactory, 也是非常核心的。
所以,我們可以直接使用 DefaultLIsttableBeanFactory , 而不使用 ApplicationContext 的某個(gè)實(shí)現(xiàn)類:
DefaultListableBeanFactory beanFactory = new DefaultListableBeanFactory();
AbstractBeanDefinition beanDefinition = BeanDefinitionBuilder.genericBeanDefinition().getBeanDefinition();
beanDefinition.setBeanClass(UserService.class);
beanFactory.registerBeanDefinition("userService", beanDefinition);
System.out.println(beanFactory.getBean("userService"));
DefaultLIsttableBeanFactory 非常強(qiáng)大,我們可以查看它的繼承關(guān)系:
從繼承關(guān)系來(lái)看,它實(shí)現(xiàn)了很多接口,具備一下功能:
1、AliasRegistry: 支持別名功能,一個(gè)名字可以對(duì)應(yīng)多個(gè)別名;
2、BeanDefinitionRegistry: 可以注冊(cè),保存,移除,獲取某個(gè) BeanDefinition;
3、SingletonBeanFactory:可以直接注冊(cè),獲取一個(gè)單例 Bean;
4、SimpleAliasRegistry: 它是一個(gè)類,實(shí)現(xiàn)了 AliasRegistry 接口中所有的定義,支持別名功能;
5、ListableBeanFactory:在 BeanFactory 的基礎(chǔ)上,增加了其他功能呢,可以獲取所有的 BeanDefinition 的定義信息。
ApplicationContext 應(yīng)用上下文
為應(yīng)用程序提供配置的上下文。這在應(yīng)用程序運(yùn)行時(shí)是只讀的,但如果實(shí)現(xiàn)支持,則可能會(huì)重新加載。ApplicationContext 提供一下功能:
- 用于訪問(wèn)應(yīng)用程序組件的Bean工廠方法。從 ListableBeanFactory 繼承;
- 以通用方式加載文件資源的能力。繼承org.springframework.core.io.ResourceLoader接口;
- 基于觀察者模式的事件注冊(cè)/發(fā)布模型實(shí)現(xiàn) Spring 事件機(jī)制。繼承 ApplicationEventPublisher 接口;
- 能夠解析國(guó)際化消息編碼,支持國(guó)際化。繼承 MessageSource 接口。
- 如果我們繼承一個(gè)父接口,那么子類的是現(xiàn)實(shí)始終優(yōu)先。例如,這意味著整個(gè)web應(yīng)用程序可以使用單個(gè)父上下文,而每個(gè)servlet都有獨(dú)立于任何其他servlet的子上下文。
除了標(biāo)準(zhǔn) BeanFactory 生命周期功能、ApplicationContext 實(shí)現(xiàn)檢測(cè)和調(diào)用 ApplicationContextAware 對(duì)象 以及 ResourceLoaderAware、ApplicationEventPublisherware 和MessageSourceAware 對(duì)象。
下面我們一起來(lái)看一下,它的兩個(gè)比較常用的實(shí)現(xiàn)類:
- AnnotationConfigApplicationContext 基于注解的 Spring 上下文,也可以說(shuō)成是 Spring 的容器
- ClassPathXmlApplicationContext 基于 XML 上線文,Spring 容器,(PS:目前較少使用,主要是 Spirng-Boot 主推注解方式)
AnnotationConfigApplicationContext
使用 AnnotationConfigApplicationContext 可以實(shí)現(xiàn)基于 Java 的配置類加載Spring的應(yīng)用上下文。不用使用spring-context.xml?進(jìn)行配置。也可以通過(guò)@Bean @Component等方式創(chuàng)建Bean, 相比 XML 配置, 更加便捷。
ClassPathXmlApplicationContext
ClassPathXmlApplicationContext 是 spring 讀取 xml 最常用的類。而我們一般操作的是它的接口ApplicationContext。BeanFactory和ApplicationContext區(qū)別不大,BeanFactory不在自動(dòng) BeanPostProcessor 和自動(dòng) BeanFactoryPostProcessor 上注冊(cè)。使用中我們盡量用ApplicationContext。
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserService UserSrv = (UserService)ctx.getBean("userService");
如果將ApplicationContext 改成 BeanFactory,是沒(méi)有任何問(wèn)題。AbstractApplicationContext有時(shí)也用這個(gè)。除了也繼承自BeanFactory和ApplicationContext外,還有一個(gè)方法registerShutdownHook(),它會(huì)讓你的Spring IoC容器關(guān)閉。當(dāng)然如果在web應(yīng)用的話,也會(huì)自動(dòng)關(guān)閉。
MessageSource 國(guó)際化
Spring 國(guó)際化可以通過(guò)定義 MessageSource Bean 然后通過(guò) ApplicationContext#getMessage 來(lái)獲取國(guó)際化配置文件中配置的 message 值。
- 定義 MessageSource:
@Bean
public MessageSource messageSource(){
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
- 創(chuàng)建完這個(gè) Bean , 我們可以在任何需要使用國(guó)際化的地方使用該 MessageSource 的 Bean 對(duì)象。
同時(shí),因?yàn)?ApplicationContext 也擁有國(guó)際化功能,所以可以直接這么使用:
context.getMessage("test", null, new Locale("en"));
通常國(guó)內(nèi)業(yè)務(wù)的項(xiàng)目很少使用,大公司或者海外項(xiàng)目使用比較多,會(huì)做多語(yǔ)言的文案內(nèi)容處理,需要公司有專業(yè)的翻譯團(tuán)隊(duì)或者外包團(tuán)隊(duì),不然中式外語(yǔ)很容易出笑話。
Resource 資源加載
ApplicationContext 還擁有資源加載的功能,加載的內(nèi)存包括本地文件,和網(wǎng)絡(luò)資源。也可以說(shuō)是一個(gè)比較實(shí)用的工具 API,因?yàn)楹芏喑鯇W(xué)者搞不清楚相對(duì)路徑,絕對(duì)路徑,classpath 等。
比如,可以直接使用ApplicationConext 獲取某個(gè)文件的內(nèi)容:
AnnotationConfigApplicationContext context = new AnnotaionConfigApplicaitonContext(AppConfig.class);
Resource resource = context.getResource("file://C:\\a.txt")
System.out.println(resource.contextLength())
通過(guò) ApplicationConext 來(lái)實(shí)現(xiàn)這個(gè)功能,可以提高我們的開(kāi)發(fā)效率。比如我們還可以這樣使用:
AnnotationConfigApplicationContext context = new AnnotaionConfigApplicaitonContext(AppConfig.class);
Resource resource = context.getResource("classpath:spring-context.xml")
System.out.println(resource.contextLength())
Resource resource2 = context.getResource("https://baidu.com");
System.out.println(resource2.getURL());
獲取多個(gè)資源:
AnnotationConfigApplicationContext context = new AnnotaionConfigApplicaitonContext(AppConfig.class);
Resource resource = context.getResource("classpath:spring-context.xml")
System.out.println(resource.contextLength())
獲取運(yùn)行時(shí)環(huán)境變量:
MapsystemEnvironment = context.getEnvironment().getSystemEnvironment();
System.out.println(systemEnvironment);
MapsystemProperties = context.getEnvironment().getSystemProperties();
System.out.println(systemProperties);
MutablePropertySources propertySources = context.getEnvironment().getPropertySources();
System.out.println(propertySources);
解析文件:
@PropertySource("classpath:spring.properties")
可以讓某一個(gè) properties 文件添加到我們的環(huán)境變量中,可以通過(guò)一下的代碼來(lái)獲?。?/p>
String abc = context.getEnvironment().getProperty("abc", "1");
System.out.println(abc);
ApplicationEvent 事件發(fā)布
ApplicationEvent 是 Spring 提供的事件驅(qū)動(dòng)編程,也可以看作觀察者模式的一個(gè)編程范本,支持同步監(jiān)聽(tīng)和異步監(jiān)聽(tīng)兩種方式。
定義事件:
public class TestEvent extends ApplicationEvent {
public TestEvent(Object source){
super(source);
}
}
定義事件監(jiān)聽(tīng)器:
public class TestListener implements ApplicationListener{
@Override
public void onApplicationEvent(TestEvent event){
System.out.println("收到一個(gè)事件 ,,,,,");
}
}
調(diào)用程序:
@Configuration
public class ApplicationEventTest {
@Bean
public ApplicationListener applicationListener(){
return new TestListener();
}
public static void main(String[] args){
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(ApplicationEventTest.class);
context.publishEvent(new TestEvent(new Object()));
}
}
Spring 容器啟動(dòng)過(guò)程中有很多啟動(dòng)過(guò)程的事件,我們可以通過(guò)這種方式來(lái)實(shí)現(xiàn),在Spring 容器啟動(dòng)過(guò)后初始化一些內(nèi)容:比如初始化系統(tǒng)參數(shù)到服務(wù)的本地內(nèi)存等。不過(guò)我們需要注意的是 Spring 的事件機(jī)制只是一個(gè)本地事件,沒(méi)有持久化機(jī)制。所以可靠性不能完全保證。
類型轉(zhuǎn)換
Spring 內(nèi)部,有很多地方可能需要將 String 轉(zhuǎn)換為其他類型,今天我們一起來(lái)學(xué)習(xí)一下 PropertyEditor、 ConversionService、TypeConverter 三種類型轉(zhuǎn)換的使用。
PropertyEditor 類型轉(zhuǎn)換器
PropertyEditor 是 JDK 提供的類型轉(zhuǎn)換器,首先創(chuàng)建 bean :
@Service
public class OrderService {
@Value("orderVal")
private Order order;
public void test(){
System.out.println("test order : " + order);
}
}
創(chuàng)建類型轉(zhuǎn)換器,將字符串轉(zhuǎn)換為 Order 實(shí)例對(duì)象。
public class String2ObjectPropertyEditor extends PropertyEditorSupport implements PropertyEditor {
@Override
public void setAsText(String text) throws IllegalArgumentException {
Order order = new Order();
order.setName("haha");
order.setAge(12);
this.setValue(order);
}
}
注冊(cè)轉(zhuǎn)換器以及測(cè)試代碼:
@Import({OrderService.class})
@Configuration
public class PropertyEditorTest {
@Bean
public CustomEditorConfigurer customEditorConfigurer(){
Map, Class extends PropertyEditor>> customEditors = new HashMap<>();
customEditors.put(Order.class, String2ObjectPropertyEditor.class);
CustomEditorConfigurer customEditorConfigurer = new CustomEditorConfigurer();
customEditorConfigurer.setCustomEditors(customEditors);
return customEditorConfigurer;
}
public static void main(String[] args){
// 使用方式 1
String2ObjectPropertyEditor propertyEditor = new String2ObjectPropertyEditor();
propertyEditor.setAsText("1");
Object value = propertyEditor.getValue();
System.out.println(value);
// 使用方式 2
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(PropertyEditorTest.class);
OrderService orderItemService = applicationContext.getBean(OrderService.class);
orderItemService.test();
}
}
ConversionService 類型轉(zhuǎn)換器
ConversionService 是 Sprign 中提供的類型轉(zhuǎn)換器,它比 PrppertyEditor 功能更加強(qiáng)大。定義轉(zhuǎn)換器:
public class String2ObjectConversionService implements ConditionalGenericConverter {
@Override
public boolean matches(TypeDescriptor sourceType, TypeDescriptor targetType){
return
Objects.equals(sourceType.getType(), String.class)
&&
Objects.equals(targetType.getType(), Order.class);
}
@Override
public Set getConvertibleTypes(){
return Collections.singleton(new ConvertiblePair(String.class, Order.class));
}
@Override
public Object convert(Object source, TypeDescriptor sourceType, TypeDescriptor targetType){
return new Order("haha", 32);
}
} 單獨(dú)使用
DefaultConversionService conversionService = new DefaultConversionService();
conversionService.addConverter(new String2ObjectConversionService());
Order order = conversionService.convert("1", Order.class);
System.out.println(order);
在 Spring 中使用:
@Bean
public ConversionServiceFactoryBean conversionService(){
ConversionServiceFactoryBean conversionServiceFactoryBean = new ConversionServiceFactoryBean();
conversionServiceFactoryBean.setConverters(Collections.singleton(new String2ObjectConversionService()));
return conversionServiceFactoryBean;
}
Bean 的注入和調(diào)用代碼:
// 測(cè)試和注入
@Service
public class OrderService {
//通過(guò) @Value 注入
@Value("orderVal")
private Order order;
public void test(){
System.out.println("test order : " + order);
}
}
// 調(diào)用代碼
ApplicationContext appliciton = new AnnotationConfigApplicationContext(ConvertTest.class);
OrderItemService orderItemService = appliciton.getBean(OrderItemService.class);
orderItemService.test();
TypeConverter 類型轉(zhuǎn)換器
TypeConverter 整合了 PropertyEditor 和 ConversionService, 在 Spring 內(nèi)部使用:
SimpleTypeConverter typeConverter = new SimpleTypeConverter();
typeConverter.registerCustomEditor(Order.class, new String2ObjectPropertyEditor());
Order order = typeConverter.convertIfNecessary("orderVal", Order.class);
System.out.println(order);
比如在 AbstractBeanFacotry#adaptBeanInstance 中也有用到:
// AbstractBeanFacotry.javaT adaptBeanInstance(String name, Object bean, @Nullable Class> requiredType){
// Check if required type matches the type of the actual bean instance.
// 如果轉(zhuǎn)換類型不為空,并且 bean 類型與目標(biāo)類型不匹配
if (requiredType != null && !requiredType.isInstance(bean)) {
try {
// 嘗試轉(zhuǎn)換
Object convertedBean = getTypeConverter().convertIfNecessary(bean, requiredType);
if (convertedBean == null) {
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
return (T) convertedBean;
}
catch (TypeMismatchException ex) {
if (logger.isTraceEnabled()) {
logger.trace("Failed to convert bean '" + name + "' to required type '" +
ClassUtils.getQualifiedName(requiredType) + "'", ex);
}
throw new BeanNotOfRequiredTypeException(name, requiredType, bean.getClass());
}
}
return (T) bean;
}
OrderComparator 比較器
OrderComparator 是 Spring 提供的一種比較器,可以根據(jù) @Order 注解或者實(shí)現(xiàn) Ordered 接口來(lái)進(jìn)行比較,從而進(jìn)行排序。如果說(shuō)我們對(duì)一個(gè) Bean 進(jìn)行排序的話,我們可以在自動(dòng)注入 List
舉個(gè)例子:
public class B implements Ordered {
@Override
public int getOrder(){
return 2;
}
}
public class A implements Ordered {
@Override
public int getOrder(){
return 1;
}
}
public class OrderComparatorTest {
public static void main(String[] args){
A a = new A();
B b = new B();
OrderComparator orderComparator = new OrderComparator();
System.out.println(orderComparator.compare(a, b)); // -1
List list = new ArrayList();
list.add(a);
list.add(b);
list.sort(orderComparator);
System.out.println(list); // a,b
}
}
另外,Spring 還提供了一個(gè) OrderComparator 的子類:AnnotationAwareOrderComparator, 它支持 ??@Order?? 注解來(lái)指定 order 的值,比如:
@Order(1)
public class A1 {
}
@Order(1)
public class B1 {
}
public class OrderComparatorTest1 {
public static void main(String[] args){
A1 a = new A1();
B1 b = new B1();
AnnotationAwareOrderComparator orderComparator = new AnnotationAwareOrderComparator();
System.out.println(orderComparator.compare(a, b)); // -1
List list = new ArrayList();
list.add(a);
list.add(b);
list.sort(orderComparator);
System.out.println(list); // a,b
}
}
BeanPostProessor 后置處理器
BeanPostProessor 表示 bean 的后置處理器,我們可以定義一個(gè)或者多個(gè) BeanPostProcessor , 比如通過(guò)如下的代碼定義:
public class TestBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
System.out.println("postProcessBeforeInitialization userService");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("userService".equals(beanName)) {
System.out.println("postProcessAfterInitialization userService");
}
return bean;
}
}
一個(gè) BeanPostProcessor 可以在任意一個(gè) Bean 的初始化之前以及初始化之后去做額外的一些用戶的自定義邏輯。
BeanFactoryPostProcessor Bean 工廠后置處理器
BeanFactoryPostProcessor 表示 Bean 工廠的后置處理器,其實(shí)和 BeanPostProcessor 類似,BeanPostProcessor 是干涉 Bean 的創(chuàng)建過(guò)程, BeanFactoryPostProcessor 是干涉 BeanFactory 的創(chuàng)建過(guò)程,我們可以這樣定義一個(gè) BeanFactoryProcessor:
@Component
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("bean factory post processor");
}
}
我們可以在 postProcessBeanFactory() 方法中對(duì) BeanFacorty 進(jìn)行拓展。
FactoryBean 定義 Bean 創(chuàng)建
上面提到,我們可以通過(guò) BeanPostProcessor 來(lái)干涉 Spring 創(chuàng)建 Bean 的過(guò)程,但是如果我們想一個(gè) Bean 完完全全由我們來(lái)創(chuàng)造,也是可以的,比如通過(guò) FactoryBean 來(lái)實(shí)現(xiàn)。
@Component
public class TestFactoryBean implements FactoryBean {
@Override
public Object getObject() throws Exception {
UserService userService = new UserService();
return userService;
}
@Override
public Class> getObjectType() {
return UserService.class;
}
}
通過(guò)上面這段代碼,我們可以創(chuàng)造一個(gè) UserService 對(duì)象,并且將它定義為一個(gè) Bean, 但是通過(guò)這種方式定義的 Bean ,只會(huì)經(jīng)過(guò)初始化后, 其他的 Spring 的生命周期不會(huì)經(jīng)歷,比如依賴注入。
通過(guò) @Bean 也可以生成一個(gè)對(duì)象作為 Bean , 那么和 FactoryBean 的區(qū)別是什么呢?其實(shí)在很多場(chǎng)景下他兩市可以替換的,但是在原理的層面來(lái)說(shuō),區(qū)別很明顯, @Bean的 Bean會(huì)經(jīng)過(guò)完整的 Bean的生命周期。
ExcludeFilter 和 IncluderFilter Bean 掃描過(guò)濾
這兩個(gè) Filter 是 Spring 掃描過(guò)中用來(lái)過(guò)濾的,ExcludeFilter 表示排除過(guò)濾器,IncluderFilter 表示包含過(guò)濾器。比如一下配置,表示掃描 ??com.?? 這個(gè)包下返回的所有類, 但是排除 UserService 類 ,也就是算它上面所有的 @Component 注解也不會(huì)成為 Bean 。
@ComponentScan(value = "com.summer.test.service",
excludeFilters = {
@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class)
})
public class AppConfig {
}
比如以下配置,就算 UserService 類上沒(méi)有 @Component 注解,它也會(huì)唄掃描成一個(gè) Bean
@ComponentScan(value = "com.summer.test.service",
includeFilters = {
@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class)
})
public class AppConfig {
}
FilterType 分為:
- ANNOTATION,
- ASSIGNABLE_TYPE,
- ASPECTJ,
- REGEX,
- CUSTOM
MetadataReader/ClassMetaData/AnnotationMetadata 元數(shù)據(jù)讀取器
元數(shù)據(jù)讀取器也是一個(gè)非常有意思的 API,我們可以通過(guò)它獲取類的描述信息,比如可以讀取自定義注解、某個(gè)類是否實(shí)現(xiàn)某接口、某個(gè)類是否存在某方法等。
常用的有以下幾個(gè)類:
- MetadataReader 元數(shù)據(jù)讀取
- ClassMetaData 類的元數(shù)據(jù)信息
- AnnotationMetadata 注解的元數(shù)據(jù)信息
測(cè)試代碼
SimpleMetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
// 構(gòu)造 MetadataReader
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader("com.summer.test.service.UserService");
// 得到一個(gè) ClassMetadata, 并且獲取類名
ClassMetadata classMetadata = metadataReader.getClassMetadata();
System.out.println(classMetadata.getClassName());
// 獲取一個(gè) AnnotationMetadata, 并且獲取該類上的注解信息
AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
System.out.println(annotationMetadata.hasMetaAnnotation(Component.class.getName())); //true
System.out.println(annotationMetadata.hasAnnotation(Component.class.getName())); //false
for (String annotationType : annotationMetadata.getAnnotationTypes()) {
// org.springframework.stereotype.Service
System.out.println(annotationType);
}
新聞標(biāo)題:一篇學(xué)會(huì)Spring核心概念
文章源于:http://m.fisionsoft.com.cn/article/djehhgg.html


咨詢
建站咨詢
