記錄常用的spring注解
1.@Configuration 和 @Bean
spring中可以使用xml 的方式進行配置, 也可以使用 @ Configuration 來指定一個類為配置類, 並使用 @Bean 來對spring容器進行注入.方法名即是id
@Configuration //聲明這個類為配置類
public class MainConfig {
//給容器中注冊一個Bean;類型為返回值的類型,id默認是用方法名作為id
@Bean("person")
public Person person01(){
return new Person("lisi", 20);
}
}
並使用如下方式獲取容器,並獲取注入的對象
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig.class); //獲取容器
Person bean = applicationContext.getBean(Person.class);//獲取對象
2. @ComponentScan 包掃描注解
在xml中,我們使用 :<context:component-scan base-package="com.test.****"/>
來進行包掃描,只要是加了 @Controller
,@service
,@Repository
,@Component
這四個注解的類,都會自動的被注入到容器中.同樣,我們也可以使用 注解的方式進行配置,在@Configuration
注解聲明的配置類上加上 @ComponentScan
注解:
@Configuration //告訴Spring這是一個配置類
@ComponentScan(value="com.test") // 掃描com.test下的類
public class MainConfig {
//給容器中注冊一個Bean;類型為返回值的類型,id默認是用方法名作為id
@Bean("person")
public Person person01(){
return new Person("lisi", 20);
}
}
在ComponentScan中還有很多屬性,可以進行定義掃描規則:
-
value : 指定掃描的包路徑
-
excludeFilters :指定掃描的時候按照什么規則排除那些組件 ,接受一個 @Filter 的數組
例:
@Filter(type=FilterType.ANNOTATION,classes={Controller.class})
, 按照注解類型的方式進行過濾(還有很多種),過濾@Controller
注解的類. -
includeFilters = Filter[] :指定掃描的時候只需要包含哪些組件, 使用方法和excludeFilters一樣,但是還要將spring的自動掃描規則關閉,才能生效(和xml相似),設置屬性 :
useDefaultFilters = false
如果需要多種過濾規則時,可以使用@ComponentScans
注解 ,可以接受多個@ComponentScan
下面是@Filter
的type屬性的詳細配置:
-
按照注解排除或注入: type=FilterType.ANNOTATION(常用)
-
按照給定的類型 : type=FilterType.ASSIGNABLE_TYPE (常用)
-
使用ASPECTJ表達式 : type=FilterType.ASPECTJ(不常用)
-
使用正則表達式 : type=FilterType.REGEX(不常用)
-
使用自定義的規則(實現TypeFilter) : type=FilterType.CUSTOM(不常用,但很靈活)
例:
public class MyTypeFilter implements TypeFilter { /** * metadataReader:讀取到的當前正在掃描的類的信息 * metadataReaderFactory:可以獲取到其他任何類信息的 */ @Override public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException { // TODO Auto-generated method stub //獲取當前類注解的信息 AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata(); //獲取當前正在掃描的類的類信息 ClassMetadata classMetadata = metadataReader.getClassMetadata(); //獲取當前類資源(類的路徑) Resource resource = metadataReader.getResource(); String className = classMetadata.getClassName(); System.out.println("--->"+className); if(className.contains("er")){ return true; } return false; } }
本例中的過濾規則是類名中帶有er的進行注入,按照返回值得true或false來決定是否注入
3.@Scope 域注解
調整注入對象的作用域,可以設置為單實例或多實例,例:
@Scope
@Bean
public Person person(){
System.out.println("給容器中添加Person....");
return new Person("張三", 25);
}
Scope注解的具體取值:
- prototype, 多實例,IOC容器在啟動時不會創建對象,每次獲取的時候才會去調用方法創建對象
- singleton,單實例,默認的取值,IOC在啟動時就會創建對象,每次獲取都是同一個對象,直接從容器中拿
- request,同一次請求創建一個實例 (不用)
- session 同一個session創建一個實例(不用)
在使用單實例加載方式的時候,在IOC容器啟動時,就創建對象,如果想要在獲取時,在創建,可以使用@Lazy
注解,使Bean懶加載
4. @Conditional 判斷Bean是否注入
在某些情況,我們需要根據情況來決定是否注入類,獲取注入不同的類,這時我們就需要使用@Conditional
注解
我們需要繼承Condition類,例:
//判斷是否liunx系統
public class LinuxCondition implements Condition {
@Override
public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
// TODO是否linux系統
//1、能獲取到ioc使用的beanfactory
ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
//2、獲取類加載器
ClassLoader classLoader = context.getClassLoader();
//3、獲取當前環境信息
Environment environment = context.getEnvironment();
//4、獲取到bean定義的注冊類(管理類,可以判斷是否注入,創建 ,刪除注入的Bean)
BeanDefinitionRegistry registry = context.getRegistry();
//獲取操作系統屬性
String property = environment.getProperty("os.name");
//可以判斷容器中的bean注冊情況,也可以給容器中注冊bean
//判斷容器中是否有person類
boolean definition = registry.containsBeanDefinition("person");
if(property.contains("linux")){
return true;
}
return false;
}
}
使用:
@Conditional(LinuxCondition.class)
@Bean("linus")
public Person person02(){
return new Person("linus", 48);
}
如果系統是liunx 才會注入該Bean ,如果不是,將不會注入, 如果將該類加載配置類上,則表示,只有當條件滿足時,才會加載配置類中的Bean
5.@Import注解 快速給容器中導入一個組件
通過注解注入對象的方式,已經有兩種,分別是:
@ComponentScan
注解進行包掃描,這主要針對自己寫的類,只有自己寫的類,才可以方便我們家@Controller/@Service/@Repository/@Component 這四個注解@Bean
向容器中注入一個對象,可以方便我們導入第三方的類
第三種方法,就是使用@Import
注解.例
@Import({Color.class,Red.class)
在配置類上加上該注解代表 向容器中注入Color類和 Red類,默認的id是類的全類名
Import注解除了可以直接指定導入的對象外,還支持更加豐富的注入方式
-
ImportSelector 的實現類:
//自定義邏輯返回需要導入的組件 public class MyImportSelector implements ImportSelector { //返回值,就是到導入到容器中的組件全類名 //AnnotationMetadata:當前標注@Import注解的類的所有注解信息 @Override public String[] selectImports(AnnotationMetadata importingClassMetadata) { // TODO Auto-generated method stub //importingClassMetadata //方法不要返回null值 return new String[]{"com.test.bean.Blue","com.test.bean.Yellow"}; } }
@Import({MyImportSelector.class})
返回的數組就是需要注入的Bean的全類名數組
-
ImportBeanDefinitionRegistrar 的實現類:
public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar { /** * AnnotationMetadata:當前類的注解信息 * BeanDefinitionRegistry:BeanDefinition注冊類; * 把所有需要添加到容器中的bean;調用 * BeanDefinitionRegistry.registerBeanDefinition手工注冊進來 */ @Override public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) { boolean definition = registry.containsBeanDefinition("com.test.bean.Red"); boolean definition2 = registry.containsBeanDefinition("com.test.bean.Blue"); if(definition && definition2){ //指定Bean定義信息;(Bean的類型,Bean。。。) RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class); //注冊一個Bean,指定bean名 registry.registerBeanDefinition("rainBow", beanDefinition); } } }
@Import({MyImportBeanDefinitionRegistrar.class})
在方法內部進行操作,使用BeanDefinitionRegistry 對象進行注入
6.FactoryBean 注冊組件
這又是一個向容器中注入對象的方法, 首先先實現 FactoryBean接口
//創建一個Spring定義的FactoryBean
public class ColorFactoryBean implements FactoryBean<Color> {
//返回一個Color對象,這個對象會添加到容器中
@Override
public Color getObject() throws Exception {
// TODO Auto-generated method stub
System.out.println("ColorFactoryBean...getObject...");
return new Color();
}
@Override
public Class<?> getObjectType() {
// TODO Auto-generated method stub
return Color.class;
}
//是單例?
//true:這個bean是單實例,在容器中保存一份
//false:多實例,每次獲取都會創建一個新的bean;
@Override
public boolean isSingleton() {
// TODO Auto-generated method stub
return false;
}
}
並將該工廠類注冊到容器中
@Bean
public ColorFactoryBean colorFactoryBean(){
return new ColorFactoryBean();
}
但是當我們通過id獲取時,卻是getObject方法返回的對象Color,如果我們想獲取到工廠對象的本身,可以在id的前面加'&' 即&colorFactoryBean
即可獲取到工廠對象的本身.
7.指定注入對象的創建和銷毀方法
在xml中,可以使用 init-method和destroy-method 兩個屬性,指定Bean的初始化方法和銷毀方法,如果使用注解,則可以用@Bean
的屬性來指定
@Bean(initMethod="init",destroyMethod="detory")
public Car car(){
return new Car();
}
如上例,就指定初始化方法為init,銷毀方法為detoty.
Bean的初始化方法是在Bean創建后,調用方法,進行賦值,Bean的銷毀方法,和Bean是否是單實例有關,如果Bean是單實例的,銷毀方法會在容器關閉時調用,如果是多例的,在從容器中取出該對象時,容器就不進行管理了,所以在容器關閉時,是不會調用銷毀方法的.
另一種方法就是實現兩個接口 ,一個是InitializingBean 實現的方法就是初始化方法, DisposableBean 實現的方法就是銷毀方法.
還有一種是使用注解標注Bean的方法 . @PostConstruct 在 Bean創建完成並且屬性賦值完成,來執行初始化方法@PreDestroy : 在容器銷毀Bean之前通知我們進行的清理工作
最后一種方式使用的是 通知的方式 實現BeanPostProcessor 接口 ,並將實現類注入到容器中,就可以實現在任何Bean的任何初始化方法執行前執行postProcessBeforeInitialization方法, 並在任何初始化方法之后執行postProcessAfterInitialization方法.(spring源碼中大量使用)
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessBeforeInitialization..."+beanName+"=>"+bean);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
// TODO Auto-generated method stub
System.out.println("postProcessAfterInitialization..."+beanName+"=>"+bean);
return bean;
}
}
8.@Value 給屬性賦值
使用@Value
注解給屬性賦值,他的使用方法 和xml文件中 value屬性一致,可以直接賦值字符串:@Value("張三")
,或者是Spring的表達式:@Value("#{20/2}")
, 也可以取出配置文件中的值(環境變量中值):@Value("${name}")
.