本節(jié)主要內(nèi)容介紹spring注解的組件注冊(cè),具體包括下面的幾個(gè)注解:
- @ComponentScan自動(dòng)掃面組件
- @Scope設(shè)置組件的作用域
- @Lazy bean組件懶加載
- @Conditional按照條件注冊(cè)Bean
- @Import給容器中導(dǎo)入一個(gè)組件
1、@ComponentScan自動(dòng)掃面組件
- 源碼
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
@Documented
//可以重復(fù)使用
@Repeatable(ComponentScans.class)
public @interface ComponentScan {
//使用包名
@AliasFor("basePackages")
String[] value() default {};
@AliasFor("value")
String[] basePackages() default {};
//使用具體類型名稱
Class<?>[] basePackageClasses() default {};
....其他屬性
//指定掃描的時(shí)候只需要包含哪些組件
Filter[] includeFilters() default {};
//指定掃描的時(shí)候按照什么規(guī)則排除那些組件
Filter[] excludeFilters() default {};
boolean lazyInit() default false;
//過濾規(guī)則類
@Retention(RetentionPolicy.RUNTIME)
@Target({})
@interface Filter {
//FilterType定義按什么過濾類型來進(jìn)行過濾非凌,
/**
FilterType.ANNOTATION:按照注解
FilterType.ASSIGNABLE_TYPE:按照給定的類型;
FilterType.ASPECTJ:使用ASPECTJ表達(dá)式
FilterType.REGEX:使用正則指定
FilterType.CUSTOM:使用自定義規(guī)則
*/
FilterType type() default FilterType.ANNOTATION;
@AliasFor("classes")
Class<?>[] value() default {};
@AliasFor("value")
Class<?>[] classes() default {};
String[] pattern() default {};
}
}
- 使用說明
1荆针、只包含有Controller注解bean
@ComponentScan(value="com.qiu",includeFilters = {
@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),}
,useDefaultFilters = false)
2敞嗡、排除含有controller注解的bean
@ComponentScan(value="com.qiu",excludeFilters = {
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
})
2、@Scope設(shè)置組件的作用域
- 源碼
//作用與類或者方法上
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Scope {
@AliasFor("scopeName")
String value() default "";
@AliasFor("value")
String scopeName() default "";
ScopedProxyMode proxyMode() default ScopedProxyMode.DEFAULT;
}
- 使用
*默認(rèn)是單實(shí)例的航背,ConfigurableBeanFactory接口含有者兩個(gè)屬性
*單實(shí)例和原型實(shí)例說明:prototype:多實(shí)例的:ioc容器啟動(dòng)并不會(huì)去調(diào)用方法創(chuàng)建對(duì)象放在容器中喉悴。
每次獲取的時(shí)候才會(huì)調(diào)用方法創(chuàng)建對(duì)象;singleton:單實(shí)例的(默認(rèn)值):ioc容器啟動(dòng)會(huì)調(diào)用方法創(chuàng)建
對(duì)象放到ioc容器中沃粗。 以后每次獲取就是直接從容器(map.get())中拿
1粥惧、原型案例
@Scope("prototype")
@Bean()
public User user() {
System.out.println("給容器中添加user....");
return new User();
}
2、測(cè)試
ConfigurableApplicationContext context2=new
AnnotationConfigApplicationContext(ScopeConfig.class);
//測(cè)試scope:獲取容器中的bean,singleton單例時(shí)候相等最盅,prototype時(shí)候不相等
User user2=(User) context2.getBean("user");
User user1=(User) context2.getBean("user");
System.out.println(user1==user2);
3突雪、@Lazy bean組件懶加載
- @Lazy注解用于標(biāo)識(shí)bean是否需要延遲加載,默認(rèn)是true涡贱。當(dāng)沒加注解之前主要容器啟動(dòng)就會(huì)實(shí)例化bean,加上@Lazy注解則必須在第一次調(diào)用的時(shí)候才會(huì)加載如下:
1咏删、沒加注解之前主要容器啟動(dòng)就會(huì)實(shí)例化bean
ConfigurableApplicationContext context2=new
AnnotationConfigApplicationContext(ScopeConfig.class);
2、加入@Lazy后必須第一次調(diào)用的時(shí)候才會(huì)加載
User user3=(User) context2.getBean("user1");
4问词、@Conditional按照條件注冊(cè)Bean
- 源碼
//作用于方法和類
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Conditional {
//參數(shù)是:繼承于Condition的類數(shù)組
Class<? extends Condition>[] value();
}
//condition接口督函,自定義的condition類需要實(shí)現(xiàn)該接口
public interface Condition {
/**
* ConditionContext:判斷條件能使用的上下文(環(huán)境)
* AnnotatedTypeMetadata:注釋信息
*/
boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata);
}
- 案例說明
需求:按照當(dāng)前操作系統(tǒng)來注入相應(yīng)的Bean,如果系統(tǒng)是windows激挪,給容器中注冊(cè)("bill")辰狡,如果是linux系統(tǒng),給容器中注冊(cè)("linus")
1垄分、判斷是否是linux系統(tǒng)
public class LinuxCondition implements Condition{
/**
* ConditionContext:判斷條件能使用的上下文(環(huán)境)
* AnnotatedTypeMetadata:注釋信息
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)
{
//1.能獲取到ioc使用的Beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2宛篇、獲取到類加載器
ClassLoader classLoader = context.getClassLoader();
//3.獲取到當(dāng)前環(huán)境信息
Environment environment = context.getEnvironment();
//4.獲取到bean定義的注冊(cè)類信息
BeanDefinitionRegistry registry = context.getRegistry();
//=============這里主要是為了獲取當(dāng)前系統(tǒng)的環(huán)境變臉
String property=environment.getProperty("os.name");
if (property.contains("linux")) {
return true;//放行
}
return false;
}
}
2、判斷是否是windows系統(tǒng)
public class WindowsCondition implements Condition{
/**
* ConditionContext:判斷條件能使用的上下文(環(huán)境)
* AnnotatedTypeMetadata:注釋信息
*/
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata)
{
Environment environment = context.getEnvironment();
String property=environment.getProperty("os.name");
if (property.contains("Windows")) {
return true;//放行
}
return false;
}
}
3薄湿、@Conditional:按照一定的邏輯進(jìn)行判斷叫倍,滿足條件給容器注入bean
public class ConditionalConfig {
//注入windows
@Conditional(value= {WindowsCondition.class})
@Bean
public User user1() {
User user=new User();
user.setUserName("bill");
return user;
}
//注入linux
@Conditional(value= {LinuxCondition.class})
@Bean
public User user2() {
User user=new User();
user.setUserName("linus");
return user;
}
4、idea中更換操作系統(tǒng)方法:-Dos.name=linux
介紹完了條件注解在spring中的使用豺瘤,在Springboot中條件注解的分類:
Class conditions:@ConditionalOnClass和@ConditionalOnMissingClass吆倦,表示類是否在類路徑下的條件注解
Bean conditions:@ConditionalOnBean和@ConditionalOnMissingBean,表示Bean是否被定義的條件注解
Property conditions:@ConditionalOnProperty坐求,使用prefix和name屬性用來表示是否有值蚕泽,默認(rèn)的話,只要該屬性存在值桥嗤,且不為false赛糟,即可匹配
Resource conditions:@ConditionalOnResource表示是否存在指定的resouce的條件注解
Web application conditions:@ConditionalOnWebApplication和@ConditionalOnNotWebApplication派任,當(dāng)項(xiàng)目是web項(xiàng)目,或者不是web項(xiàng)目的條件注解
SpEL expression conditions:@ConditionalOnExpression璧南,根據(jù)SPEL表達(dá)式執(zhí)行結(jié)果作為條件
5、@Import給容器中導(dǎo)入一個(gè)組件
- 源碼
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Import {
//只有一個(gè)屬性师逸,類型數(shù)組
Class<?>[] value();
}
- 給容器中注冊(cè)組件方式:
1司倚、包掃描+組件標(biāo)注注解(@Controller/@Service/@Repository/@Component)[自己寫的類]
2、@Bean[導(dǎo)入的第三方包里面的組件或者自己寫的]
3篓像、@Import[快速給容器中導(dǎo)入一個(gè)組件动知,常用于框架中]
(1)、@Import(要導(dǎo)入到容器中的組件)员辩;容器中就會(huì)自動(dòng)注冊(cè)這個(gè)組件盒粮,id默認(rèn)是全類名
(2)、ImportSelector:返回需要導(dǎo)入的組件的全類名數(shù)組奠滑;
(3)丹皱、ImportBeanDefinitionRegistrar:手動(dòng)注冊(cè)bean到容器中
4、使用Spring提供的 FactoryBean(工廠Bean);
(1)默認(rèn)獲取到的是工廠bean調(diào)用getObject創(chuàng)建的對(duì)象
- @Import注入組件案例說明:
1宋税、@Import(要導(dǎo)入到容器中的組件)
@Import(value= {Person.class})
2摊崭、ImportSelector:返回需要導(dǎo)入的組件的全類名數(shù)組;
//先自定義邏輯返回需要導(dǎo)入的組件
public class MyImportSelector implements ImportSelector {
//返回值杰赛,就是到導(dǎo)入到容器中的組件全類名
//AnnotationMetadata:當(dāng)前標(biāo)注@Import注解的類的所有注解信息
public String[] selectImports(AnnotationMetadata importingClassMetadata) {
//importingClassMetadata
//方法不要返回null值
return new String[]{"com.huya.qiu.model.BlackPerson",
"com.huya.qiu.model.WhitePerson"};
}
}
//然后注入
@Import(value= {MyImportSelector.class})
3呢簸、ImportBeanDefinitionRegistrar:手動(dòng)注冊(cè)bean到容器中
//先實(shí)現(xiàn)ImportBeanDefinitionRegistrar接口
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {
/**
* AnnotationMetadata:當(dāng)前類的注解信息
* BeanDefinitionRegistry:BeanDefinition注冊(cè)類;
* 把所有需要添加到容器中的bean乏屯;調(diào)用
* BeanDefinitionRegistry.registerBeanDefinition手工注冊(cè)進(jìn)來
*/
public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
//當(dāng)同時(shí)擁有下面兩個(gè)注冊(cè)bean時(shí)候也注冊(cè)yellowPerson
boolean definition = registry.containsBeanDefinition("com.huya.qiu.model.BlackPerson");
boolean definition2 = registry.containsBeanDefinition("com.huya.qiu.model.WhitePerson");
if(definition && definition2){
//指定Bean定義信息根时;(Bean的類型,Bean辰晕。蛤迎。。)
RootBeanDefinition beanDefinition = new RootBeanDefinition(YellowPerson.class);
//注冊(cè)一個(gè)Bean伞芹,指定bean名
registry.registerBeanDefinition("yellowPerson", beanDefinition);
}
}
}
//然后注入
@Import(value= {MyImportBeanDefinitionRegistrar.class})
- 使用Spring提供的 FactoryBean注入組價(jià)案例說明
1忘苛、創(chuàng)建一個(gè)Spring定義的FactoryBean
public class PersonFactoryBean implements FactoryBean<Person> {
//返回一個(gè)Person對(duì)象,這個(gè)對(duì)象會(huì)添加到容器中
public Person getObject() throws Exception {
System.out.println("PersonFactoryBean...getObject...");
return new Person();
}
public Class<?> getObjectType() {
return Person.class;
}
//是單例唱较?
public boolean isSingleton() {
return false;
}
}
2扎唾、注入相應(yīng)的bean
@Bean
public PersonFactoryBean personFactoryBean(){
return new PersonFactoryBean();
}