Spring注解驅動(上)


記錄常用的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中還有很多屬性,可以進行定義掃描規則:

  1. value : 指定掃描的包路徑

  2. excludeFilters :指定掃描的時候按照什么規則排除那些組件 ,接受一個 @Filter 的數組

    例:@Filter(type=FilterType.ANNOTATION,classes={Controller.class}), 按照注解類型的方式進行過濾(還有很多種),過濾@Controller注解的類.

  3. includeFilters = Filter[] :指定掃描的時候只需要包含哪些組件, 使用方法和excludeFilters一樣,但是還要將spring的自動掃描規則關閉,才能生效(和xml相似),設置屬性 :useDefaultFilters = false

如果需要多種過濾規則時,可以使用@ComponentScans 注解 ,可以接受多個@ComponentScan


下面是@Filter 的type屬性的詳細配置:

  1. 按照注解排除或注入: type=FilterType.ANNOTATION(常用)

  2. 按照給定的類型 : type=FilterType.ASSIGNABLE_TYPE (常用)

  3. 使用ASPECTJ表達式 : type=FilterType.ASPECTJ(不常用)

  4. 使用正則表達式 : type=FilterType.REGEX(不常用)

  5. 使用自定義的規則(實現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注解的具體取值:

  1. prototype, 多實例,IOC容器在啟動時不會創建對象,每次獲取的時候才會去調用方法創建對象
  2. singleton,單實例,默認的取值,IOC在啟動時就會創建對象,每次獲取都是同一個對象,直接從容器中拿
  3. request,同一次請求創建一個實例 (不用)
  4. 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注解 快速給容器中導入一個組件

通過注解注入對象的方式,已經有兩種,分別是:

  1. @ComponentScan注解進行包掃描,這主要針對自己寫的類,只有自己寫的類,才可以方便我們家@Controller/@Service/@Repository/@Component 這四個注解
  2. @Bean 向容器中注入一個對象,可以方便我們導入第三方的類

第三種方法,就是使用@Import 注解.例

@Import({Color.class,Red.class)

在配置類上加上該注解代表 向容器中注入Color類和 Red類,默認的id是類的全類名

Import注解除了可以直接指定導入的對象外,還支持更加豐富的注入方式

  1. 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的全類名數組

  2. 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}").


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM