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

霞山網(wǎng)站制作公司哪家好,找創(chuàng)新互聯(lián)!從網(wǎng)頁設(shè)計、網(wǎng)站建設(shè)、微信開發(fā)、APP開發(fā)、響應(yīng)式網(wǎng)站建設(shè)等網(wǎng)站項目制作,到程序開發(fā),運營維護。創(chuàng)新互聯(lián)從2013年成立到現(xiàn)在10年的時間,我們擁有了豐富的建站經(jīng)驗和運維經(jīng)驗,來保證我們的工作的順利進行。專注于網(wǎng)站建設(shè)就選創(chuàng)新互聯(lián)。
BeanDefinition Bean 定義信息
BeanDefinition 表示 Bean 的定義, BeanDefinition 中存在很多屬性來描述 Bean 的特征。比如:
- class, 表示 bean 的類型
- scope, 表示 bean 的作用域,單例(_singleton_)或者原型(_prototype_)
- lazyInit, 表示 bean 是否懶加載
- initMethodName, 表示 bean 的初始化需要執(zhí)行的方法
- destoryMethodName, 表示 bean 銷毀時需要執(zhí)行 bean 的方法
- and more ...
他的 Bean 屬性方法關(guān)系圖如下:
在 Spring 中,我們可以通過一下幾種方式來定義 bean 1、xml 方式,可以通過 標(biāo)簽定義一個 bean 2、注解方式,可以通過 @Bean、@Component(@Service, @Controller,@Repository) 這幾種方式,我們稱為 申明式定義 Bean
我們還可以通過編程式定義 bean, 比如直接通過 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);
//注冊 bean
applicationContext.registerBeanDefinition("orderService", beanDefinition);
applicationContext.refresh();
System.out.println(applicationContext.getBean("orderService"));
}
}
class OrderService {
}
類比申明式事務(wù),編程式事務(wù),通過 、@Bean 、@Component 等申明方式所定義的 Bean , 最終都會被 Spring 解析為對應(yīng)的 BeanDefinition 對象,并且放入 Spring 容器中。
BeanDefinitionReader Bean定義讀取器
BeanDefinitionReader 是 Spring 容器中提供的 BeanDefinition 讀取器,用于將 Spring 的配置信息,轉(zhuǎn)換為 BeanDefinition 。提供了4個實現(xiàn)類:
- AbstractBeanDefinitionReader:是一個抽象類,同時實現(xiàn)了 EnvironmentCapable 接口,提供環(huán)境的get和set方法。它實現(xiàn)了BeanDefinitionReader 的一些通用方法,比如按照路徑來讀取 Bean 定義信息的方法→int loadBeanDefinitions(String location)。對于更為具體的方法,比如根據(jù)資源來讀取 Bean 定義信息的方法→int loadBeanDefinitions(Resource resource), 則交由子類來實現(xiàn)。
- PropertiesBeanDefinitionReader:是一個具體實現(xiàn)類,可以從properties文件讀取Bean定義信息。
- XmlBeanDefinitionReader:具體實現(xiàn)類,可以從XML文件讀取Bean定義信息。
- GroovyBeanDefinitionReader:具體實現(xiàn)類,可以讀取Groovy 語言寫的Bean的定義信息。
這些 BeanDefinitionReader 在我們使用 Spring 開的時候較少使用,在 Spring 源碼中使用的比較多,相當(dāng)于是 Spring 內(nèi)部的基礎(chǔ)設(shè)施。
AnnotatedBeanDefinitionReader
可以直接把類轉(zhuǎn)換為 BeanDefinition , 并且會解析類上的注解,例如:
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 類似,它可以進行掃描,掃描某個包路徑,對掃描到的類進行解析,比如,掃描到的類上如果存在 @Component 注解,那么就會把這個類解析為一個 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 的子類,通過ListableBeanFactory 繼承了 BeanFactory 接口,還實現(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 更加強大, ApplicationContext 還實現(xiàn)了其他的基礎(chǔ)接口。比如:MessageSource 國際化, ApplicationEventPublisher 事件發(fā)布, EnvironmentCapable 獲取環(huán)境變量等等,關(guān)于 ApplicationContext 后面詳細(xì)展開。
在 Spring 源碼的實現(xiàn)中,當(dāng)我們創(chuàng)建一個 ApplicationContext 時,也是創(chuàng)建 BeanFactory 的一個實例, 相當(dāng)于使用了 ApplicationContext 的某些方法時,比如 getBean() , 也是就是調(diào)用的 BeanFactory 的 getBean()。
在 Spring 源碼中, BeanFactory 接口存在一個非常重要的實現(xiàn)類:DefaultLIsttableBeanFactory, 也是非常核心的。
所以,我們可以直接使用 DefaultLIsttableBeanFactory , 而不使用 ApplicationContext 的某個實現(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 非常強大,我們可以查看它的繼承關(guān)系:
從繼承關(guān)系來看,它實現(xiàn)了很多接口,具備一下功能:
1、AliasRegistry: 支持別名功能,一個名字可以對應(yīng)多個別名;
2、BeanDefinitionRegistry: 可以注冊,保存,移除,獲取某個 BeanDefinition;
3、SingletonBeanFactory:可以直接注冊,獲取一個單例 Bean;
4、SimpleAliasRegistry: 它是一個類,實現(xiàn)了 AliasRegistry 接口中所有的定義,支持別名功能;
5、ListableBeanFactory:在 BeanFactory 的基礎(chǔ)上,增加了其他功能呢,可以獲取所有的 BeanDefinition 的定義信息。
ApplicationContext 應(yīng)用上下文
為應(yīng)用程序提供配置的上下文。這在應(yīng)用程序運行時是只讀的,但如果實現(xiàn)支持,則可能會重新加載。ApplicationContext 提供一下功能:
- 用于訪問應(yīng)用程序組件的Bean工廠方法。從 ListableBeanFactory 繼承;
- 以通用方式加載文件資源的能力。繼承org.springframework.core.io.ResourceLoader接口;
- 基于觀察者模式的事件注冊/發(fā)布模型實現(xiàn) Spring 事件機制。繼承 ApplicationEventPublisher 接口;
- 能夠解析國際化消息編碼,支持國際化。繼承 MessageSource 接口。
- 如果我們繼承一個父接口,那么子類的是現(xiàn)實始終優(yōu)先。例如,這意味著整個web應(yīng)用程序可以使用單個父上下文,而每個servlet都有獨立于任何其他servlet的子上下文。
除了標(biāo)準(zhǔn) BeanFactory 生命周期功能、ApplicationContext 實現(xiàn)檢測和調(diào)用 ApplicationContextAware 對象 以及 ResourceLoaderAware、ApplicationEventPublisherware 和MessageSourceAware 對象。
下面我們一起來看一下,它的兩個比較常用的實現(xiàn)類:
- AnnotationConfigApplicationContext 基于注解的 Spring 上下文,也可以說成是 Spring 的容器
- ClassPathXmlApplicationContext 基于 XML 上線文,Spring 容器,(PS:目前較少使用,主要是 Spirng-Boot 主推注解方式)
AnnotationConfigApplicationContext
使用 AnnotationConfigApplicationContext 可以實現(xiàn)基于 Java 的配置類加載Spring的應(yīng)用上下文。不用使用spring-context.xml?進行配置。也可以通過@Bean @Component等方式創(chuàng)建Bean, 相比 XML 配置, 更加便捷。
ClassPathXmlApplicationContext
ClassPathXmlApplicationContext 是 spring 讀取 xml 最常用的類。而我們一般操作的是它的接口ApplicationContext。BeanFactory和ApplicationContext區(qū)別不大,BeanFactory不在自動 BeanPostProcessor 和自動 BeanFactoryPostProcessor 上注冊。使用中我們盡量用ApplicationContext。
ApplicationContext ctx = new ClassPathXmlApplicationContext("beans.xml");
UserService UserSrv = (UserService)ctx.getBean("userService");
如果將ApplicationContext 改成 BeanFactory,是沒有任何問題。AbstractApplicationContext有時也用這個。除了也繼承自BeanFactory和ApplicationContext外,還有一個方法registerShutdownHook(),它會讓你的Spring IoC容器關(guān)閉。當(dāng)然如果在web應(yīng)用的話,也會自動關(guān)閉。
MessageSource 國際化
Spring 國際化可以通過定義 MessageSource Bean 然后通過 ApplicationContext#getMessage 來獲取國際化配置文件中配置的 message 值。
- 定義 MessageSource:
@Bean
public MessageSource messageSource(){
ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
messageSource.setBasename("messages");
return messageSource;
}
- 創(chuàng)建完這個 Bean , 我們可以在任何需要使用國際化的地方使用該 MessageSource 的 Bean 對象。
同時,因為 ApplicationContext 也擁有國際化功能,所以可以直接這么使用:
context.getMessage("test", null, new Locale("en"));
通常國內(nèi)業(yè)務(wù)的項目很少使用,大公司或者海外項目使用比較多,會做多語言的文案內(nèi)容處理,需要公司有專業(yè)的翻譯團隊或者外包團隊,不然中式外語很容易出笑話。
Resource 資源加載
ApplicationContext 還擁有資源加載的功能,加載的內(nèi)存包括本地文件,和網(wǎng)絡(luò)資源。也可以說是一個比較實用的工具 API,因為很多初學(xué)者搞不清楚相對路徑,絕對路徑,classpath 等。
比如,可以直接使用ApplicationConext 獲取某個文件的內(nèi)容:
AnnotationConfigApplicationContext context = new AnnotaionConfigApplicaitonContext(AppConfig.class);
Resource resource = context.getResource("file://C:\\a.txt")
System.out.println(resource.contextLength())
通過 ApplicationConext 來實現(xiàn)這個功能,可以提高我們的開發(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());
獲取多個資源:
AnnotationConfigApplicationContext context = new AnnotaionConfigApplicaitonContext(AppConfig.class);
Resource resource = context.getResource("classpath:spring-context.xml")
System.out.println(resource.contextLength())
獲取運行時環(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")
可以讓某一個 properties 文件添加到我們的環(huán)境變量中,可以通過一下的代碼來獲取:
String abc = context.getEnvironment().getProperty("abc", "1");
System.out.println(abc);
ApplicationEvent 事件發(fā)布
ApplicationEvent 是 Spring 提供的事件驅(qū)動編程,也可以看作觀察者模式的一個編程范本,支持同步監(jiān)聽和異步監(jiān)聽兩種方式。
定義事件:
public class TestEvent extends ApplicationEvent {
public TestEvent(Object source){
super(source);
}
}
定義事件監(jiān)聽器:
public class TestListener implements ApplicationListener{
@Override
public void onApplicationEvent(TestEvent event){
System.out.println("收到一個事件 ,,,,,");
}
}
調(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 容器啟動過程中有很多啟動過程的事件,我們可以通過這種方式來實現(xiàn),在Spring 容器啟動過后初始化一些內(nèi)容:比如初始化系統(tǒng)參數(shù)到服務(wù)的本地內(nèi)存等。不過我們需要注意的是 Spring 的事件機制只是一個本地事件,沒有持久化機制。所以可靠性不能完全保證。
類型轉(zhuǎn)換
Spring 內(nèi)部,有很多地方可能需要將 String 轉(zhuǎn)換為其他類型,今天我們一起來學(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 實例對象。
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);
}
}
注冊轉(zhuǎn)換器以及測試代碼:
@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 功能更加強大。定義轉(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);
}
} 單獨使用
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)用代碼:
// 測試和注入
@Service
public class OrderService {
//通過 @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 注解或者實現(xiàn) Ordered 接口來進行比較,從而進行排序。如果說我們對一個 Bean 進行排序的話,我們可以在自動注入 List
舉個例子:
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 還提供了一個 OrderComparator 的子類:AnnotationAwareOrderComparator, 它支持 ??@Order?? 注解來指定 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 的后置處理器,我們可以定義一個或者多個 BeanPostProcessor , 比如通過如下的代碼定義:
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;
}
}
一個 BeanPostProcessor 可以在任意一個 Bean 的初始化之前以及初始化之后去做額外的一些用戶的自定義邏輯。
BeanFactoryPostProcessor Bean 工廠后置處理器
BeanFactoryPostProcessor 表示 Bean 工廠的后置處理器,其實和 BeanPostProcessor 類似,BeanPostProcessor 是干涉 Bean 的創(chuàng)建過程, BeanFactoryPostProcessor 是干涉 BeanFactory 的創(chuàng)建過程,我們可以這樣定義一個 BeanFactoryProcessor:
@Component
public class TestBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
@Override
public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
System.out.println("bean factory post processor");
}
}
我們可以在 postProcessBeanFactory() 方法中對 BeanFacorty 進行拓展。
FactoryBean 定義 Bean 創(chuàng)建
上面提到,我們可以通過 BeanPostProcessor 來干涉 Spring 創(chuàng)建 Bean 的過程,但是如果我們想一個 Bean 完完全全由我們來創(chuàng)造,也是可以的,比如通過 FactoryBean 來實現(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;
}
}
通過上面這段代碼,我們可以創(chuàng)造一個 UserService 對象,并且將它定義為一個 Bean, 但是通過這種方式定義的 Bean ,只會經(jīng)過初始化后, 其他的 Spring 的生命周期不會經(jīng)歷,比如依賴注入。
通過 @Bean 也可以生成一個對象作為 Bean , 那么和 FactoryBean 的區(qū)別是什么呢?其實在很多場景下他兩市可以替換的,但是在原理的層面來說,區(qū)別很明顯, @Bean的 Bean會經(jīng)過完整的 Bean的生命周期。
ExcludeFilter 和 IncluderFilter Bean 掃描過濾
這兩個 Filter 是 Spring 掃描過中用來過濾的,ExcludeFilter 表示排除過濾器,IncluderFilter 表示包含過濾器。比如一下配置,表示掃描 ??com.?? 這個包下返回的所有類, 但是排除 UserService 類 ,也就是算它上面所有的 @Component 注解也不會成為 Bean 。
@ComponentScan(value = "com.summer.test.service",
excludeFilters = {
@ComponentScan.Filter(
type = FilterType.ASSIGNABLE_TYPE,
classes = UserService.class)
})
public class AppConfig {
}
比如以下配置,就算 UserService 類上沒有 @Component 注解,它也會唄掃描成一個 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ù)讀取器也是一個非常有意思的 API,我們可以通過它獲取類的描述信息,比如可以讀取自定義注解、某個類是否實現(xiàn)某接口、某個類是否存在某方法等。
常用的有以下幾個類:
- MetadataReader 元數(shù)據(jù)讀取
- ClassMetaData 類的元數(shù)據(jù)信息
- AnnotationMetadata 注解的元數(shù)據(jù)信息
測試代碼
SimpleMetadataReaderFactory metadataReaderFactory = new SimpleMetadataReaderFactory();
// 構(gòu)造 MetadataReader
MetadataReader metadataReader = metadataReaderFactory.getMetadataReader("com.summer.test.service.UserService");
// 得到一個 ClassMetadata, 并且獲取類名
ClassMetadata classMetadata = metadataReader.getClassMetadata();
System.out.println(classMetadata.getClassName());
// 獲取一個 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);
}
網(wǎng)站標(biāo)題:一篇學(xué)會Spring核心概念
URL分享:http://www.dlmjj.cn/article/djehhgg.html


咨詢
建站咨詢
