1. 程式人生 > >【Spring註解】1、Spring元件註冊

【Spring註解】1、Spring元件註冊

1、@Configuration:

指定該註解的類是個配置類,對應之前的配置檔案

 

2、@Bean:

指定該方法作為一個Bean元件,它會往容器中註冊一個Bean元件;

其中型別為返回值,id預設為方法名;

也可以使用@Bean註解的name屬性,來自定義id。

 

 

3、@ComponentScans:

可以配置多個@ComponentScan

3.1、@ComponentScan:

指定要掃描的包路徑

  • excludeFilters=Filter[]: 指定掃描的時候要排除的元件。

  • useDefaultFilters: 過濾策略,預設為true,即會自動掃描帶@Component註解(包括@Component@Controller@Service@Repository註解的類)。

  • includeFilters=Filter[]: 指定掃描符合規則的元件,如果只是想掃描某些指定元件,需要將useDefaultFilters設為false,禁用預設的掃描策略。

 

3.1.1、Filter型別:

  • FilterType.ANNOTATION: 按照註解
@Filter(type = FilterType.ANNOTATION, classes = {Controller.class})

        使用@Controller註解的類符合以上規則。

 

  • FilterType.ASSIGNABLE_TYPE: 按照給定的型別
@Filter(type = FilterType.ASSIGNABLE_TYPE, classes = xxx.class)

        符合xxx.java的類符合以上規則。

 

  • FilterType.ASPECTJ: 按照ASPECTJ表示式
  • FilterType.REGEX: 按照正則表示式
  • FilterType.CUSTOM
    : 使用自定義規則

        要使用該策略,類必須實現org.springframework.core.type.filter.TypeFilter介面。

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);
		//簡單測試,如果掃描的類名中包含了er,則匹配
		if(className.contains("er")){
			return true;
		}
		return false;
	}
}

同時標註:

@Filter(type = FilterType.CUSTOM, classes = {MyTypeFilter.class})

        這樣,在掃描的時候會將包含"er"字母的類加入到容器中。

 

4、@Scope:

指定元件的作用域,預設為單例:singleton

singleton:單例項,當ioc容器啟動會呼叫方法建立物件並放到ioc容器中,而以後每次獲取物件的時候直接從ioc容器中獲取。

prototype:多例項,ioc容器啟動並不會去呼叫方法建立物件,而是在每次獲取的時候才會去呼叫方法建立物件,所以每次獲取的物件都是不一樣的。

@Scope(scopeName = ConfigurableBeanFactory.SCOPE_PROTOTYPE)
@Bean
public Book book(){
    System.out.println("建立book例項...");
    return new Book();
}

@Bean
public Person person(){//預設單例項
    System.out.println("建立person例項...");
    return new Person("zhangsan", 20);
}

測試:

AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig2.class);

//單例項
Object obj1 = applicationContext.getBean("person");
Object obj2 = applicationContext.getBean("person");
System.out.println(obj1 == obj2);//輸出true

//多例項
Object obj3 = applicationContext.getBean("book");
Object obj4 = applicationContext.getBean("book");
System.out.println(obj3 == obj4);//輸出false

 

5、@Lazy:

懶載入:只針對於單例項物件

預設載入Bean是在容器啟動的時候就會去建立物件,並將其放入ioc容器中;而懶載入則相反,容器啟動時不建立物件,而是在第一次使用(獲取)物件的時候,才會去建立物件,再將其加入到ioc容器中,之後每次再獲取該物件的時候,直接從ioc容器中獲取,不再重新建立。

@Lazy
@Bean
public Book book2(){
    System.out.println("建立book2例項...");
    return new Book();
}

 

6、@Conditional:

該註解可以標註在類上,也可以標註在方法上

方法級別:根據條件建立bean,只有滿足條件才會建立bean;

類級別:根據條件建立配置類,只有滿足條件才會去建立配置類,如果不滿足,則不會建立該配置類,同時配置類裡的bean也就不會被建立。

配置類:

@Configuration
public class MyConfig3 {

	@Conditional(WindowsCondition.class)
	@Bean("bill")
	public Person person1(){
		return new Person("bill gates", 60);
	}
	
	@Conditional(LinuxCondition.class)
	@Bean("linus")
	public Person person2(){
		return new Person("linus", 50);
	}
}

 LinuxCondition條件類:

//判斷是否是Linux系統
public class LinuxCondition implements Condition{

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// TODO Auto-generated method stub
		//獲取到ioc使用的BeanFactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		
		//獲取類載入器
		ClassLoader classLoader = context.getClassLoader();
		
		//獲取當前環境變數
		Environment environment = context.getEnvironment();
		
		//獲取到bean定義的註冊類
		BeanDefinitionRegistry registry = context.getRegistry();
		
		//獲取系統環境
		String systemName = environment.getProperty("os.name");
		if(systemName.contains("Linux")){
			return true;
		}
		return false;
	}

}

WindowsCondition條件類:

//判斷是否是Windows系統
public class WindowsCondition implements Condition {

	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// TODO Auto-generated method stub
		// 獲取當前環境變數
		Environment environment = context.getEnvironment();
		// 獲取系統環境
		String systemName = environment.getProperty("os.name");
		if (systemName.contains("Windows")) {
			return true;
		}
		return false;
	}

}

這樣,使用不同的作業系統,建立的Bean也就不一樣。

 

7、Spring匯入元件的方式:

Spring匯入元件的方式:

1、使用註解@Component@Controller@Service@Repository

2、使用@Bean匯入第三方元件

3、使用@Import快速匯入一個或多個第三方元件

3.1、指定類

3.2、使用ImportSelector介面

3.3、使用ImportBeanDefinitionRegistrar介面

4、 FactoryBean介面

 

7.1、@Import

7.1.1、指定類

假設有兩個顏色類:Red.java和Green.class,可以在配置類上使用@Import註解註冊該兩個類。

@Import({Red.class, Green.class})

這樣在Bean定義的登錄檔裡有其兩個元件,其元件的id為全類名

 

7.1.2、ImportSelector介面

需要實現ImportSelector介面

public class MyImportSelector implements ImportSelector {

	//返回值就是要匯入到容器中的元件全類名
	//AnnotationMetadata:當前標註@Import註解的類的所有註解資訊
	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		// TODO Auto-generated method stub
		//方法不要返回null
		return new String[]{"org.com.cay.spring.annotation.color.Blue", "org.com.cay.spring.annotation.color.Yellow"};
	}
}

匯入:

@Import({Red.class, Green.class, MyImportSelector.class})

這樣不僅會將@Import註解中指定的類加入到容器中,同樣會將MyImportSelector#selectImports中方法返回的全類名進行註冊到容器中。

 

7.1.3、ImportBeanDefinitionRegistrar介面

實現ImportBeanDefinitionRegistrar介面,實現registerBeanDefinitions方法,手動註冊bean。

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * AnnotationMetadata:當前類的註解資訊
	 * 
	 * BeanDefinitionRegistry:BeanDefinition註冊類
	 * 		把所有需要新增到容器中的bean,手動通過{@link BeanDefinitionRegistry#registerBeanDefinition(String, BeanDefinition)}進行註冊
	 */
	@Override
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		// TODO Auto-generated method stub

        //因為Yellow這個Bean是通過@Import匯入的,所以bean的id為全類名,所以這裡需要判斷全類名才行
		boolean hasBean = registry.containsBeanDefinition("org.com.cay.spring.annotation.color.Yellow");
		System.out.println(">>>>>>hasBean: " + hasBean);
		if(hasBean){
			BeanDefinition beanDefinition = new RootBeanDefinition(Tiger.class);
			registry.registerBeanDefinition("tiger", beanDefinition);
		}
	}
}

新增該實現類到@Import屬性中:

@Import({ Red.class, Green.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class }) 

 

7.2、FactoryBean介面

實現FactoryBean介面

public class ColorFactory implements FactoryBean<Color>{

	//返回一個Color物件,這個物件會新增到容器中
	@Override
	public Color getObject() throws Exception {
		// TODO Auto-generated method stub
		return new Color();
	}

	@Override
	public Class<?> getObjectType() {
		// TODO Auto-generated method stub
		return Color.class;
	}

	@Override
	public boolean isSingleton() {
		// TODO Auto-generated method stub
		return true;
	}
}

並將該factoryBean註冊到容器中:

@Configuration
@Import({ Red.class, Green.class, MyImportSelector.class, MyImportBeanDefinitionRegistrar.class })
public class MyConfig4 {

	@Bean
	public ColorFactory colorFactory(){
		return new ColorFactory();
	}
}

測試:

@Test
public void testFactoryBean(){
    AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig4.class);
    String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
    Arrays.asList(beanDefinitionNames).stream().forEach(System.out::println);

	//獲取到的是實現FactoryBean介面後通過getObject返回的實際bean
    Object bean = applicationContext.getBean("colorFactory");
    System.out.println("bean的型別: " + bean.getClass());
    
    //獲取factorybean自身bean
    //org.springframework.beans.factory.BeanFactory.FACTORY_BEAN_PREFIX = "&";
    Object bean2 = applicationContext.getBean("&colorFactory");
    System.out.println("bean2的型別: " + bean2.getClass());
}

為何使用"&"?

package org.springframework.beans.factory;
public interface BeanFactory {
    
    /**
     * Used to dereference a {@link FactoryBean} instance and distinguish it from
     * beans <i>created</i> by the FactoryBean. For example, if the bean named
     * {@code myJndiObject} is a FactoryBean, getting {@code &myJndiObject}
     * will return the factory, not the instance returned by the factory.
    */
	String FACTORY_BEAN_PREFIX = "&";
    
    //other...
}

 

 

====================打個廣告,歡迎關注====================

QQ:

412425870

微信公眾號:Cay課堂

csdn部落格:

http://blog.csdn.net/caychen

碼雲:

https://gitee.com/caychen/

github:

https://github.com/caychen

點選群號或者掃描二維碼即可加入QQ群:

328243383(1群)

 

點選群號或者掃描二維碼即可加入QQ群:
180479701(2群)

--------------------- 作者:caychen 來源:CSDN 原文:https://blog.csdn.net/caychen/article/details/82887926?utm_source=copy 版權宣告:本文為博主原創文章,轉載請附上博文連結!