1. 程式人生 > 其它 >Spring中的註解_學習筆記

Spring中的註解_學習筆記

技術標籤:springspring

1. @Configuration 配置註解

用xml的配置方式時匯入元件至容器時需要在xml新增標籤,並進行賦值等,利用註解的方式後只需新建一個配置類,在類上新增@Configuration,類中寫相應的方法,返回需要的型別即可,需要在方法上新增@bean註解; 這種方式的元件名為預設為方法名;

2. @ComponentScan 掃描註解

spring預設掃描只會掃描啟動類所在包及子包,需要指定包掃描路徑,以前用xml配置需要新增<context:component-scan base-package="com.xxx"/>

,採用註解開發後,只需在啟動類上新增@ComponentScan註解,並指定路徑即可;省略了配置檔案新增包掃描。

@ComponentScan("com.atguigu")
public class MainFunction {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainFunction.class);
		String[] names = context.
getBeanDefinitionNames(); for(String name:names) { System.out.println(name); } } }

親測: 其實新增包掃描註解可以在任何一個元件上指定,且可以多次指定;

//@ComponentScan("com.atguigu")
public class MainFunction {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext
(UserDao.class); String[] names = context.getBeanDefinitionNames(); for(String name:names) { System.out.println(name); } } } // @Repository //@ComponentScan("com.atguigu") @ComponentScan("com.atguigu.config") public class UserDao { }

上面把啟動類上的包掃描注掉,啟動時載入UserDao元件,而在UserDao元件中再新增掃描路徑,可得到不同的輸出結果;
注: 掃描的前提,該元件必須標註了spring容器能夠識別的標識(註解);

2.1 @ComponentScan註解中的屬性

value:指定要掃描件的包
excludeFilters: 指定掃描的 時候按照什麼規則排除那些元件;
includeFilters : 指定掃描的時候只需要包含哪些元件; 這個生效必須指定useDefaultFilters = false
此三個屬性都可以放陣列;

@ComponentScan(value = "com.atguigu",includeFilters = {@Filter(type =FilterType.ANNOTATION,classes = {Controller.class} )}
                                            ,excludeFilters = {@Filter(type = FilterType.ANNOTATION,classes = {Service.class})} ,useDefaultFilters = false)
public class MainFunction {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainFunction.class);
		String[] names = context.getBeanDefinitionNames();
		for(String name:names) {
			System.out.println(name);
		}
	}
}

2.2 掃描過濾的型別

@Filter註解中,type的型別可以是:
FilterType.ANNOTATION : 按照註解
FIlterType.ASSIGNABLE_TYPE : 按照給定的型別;
FilterType.ASPECTJ : 使用ASPECTJ表示式
FilterType.REGEX : 使用正則指定
FilterType.CUSTOM : 使用自定義規則

2.2.1 自定義過濾型別

僅需實現TypeFilter介面即可,例如:⬇

public class MyTypeFilter implements TypeFilter{

	/**
	 * metadataReader :讀取到的當前正在掃描的類的資訊
	 * metadataReaderFactory : 可以獲取到其他任何類資訊的
	 */
	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();
		System.out.println("------->"+resource);
//		String className = classMetadata.getClassName();
//		System.out.println(">>>>>>>>>>>>>>>>>"+className);
		//邏輯....
		return false;
	}
}
@ComponentScan(value = "com.atguigu",includeFilters = @Filter(type = FilterType.CUSTOM,classes =MyTypeFilter.class),useDefaultFilters = false)
public class MainFunction {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainFunction.class);
		String[] names = context.getBeanDefinitionNames();
		for(String name:names) {
			System.out.println(name);
		}
	}
}

注: 使用自定義掃描時,指定的路徑下會掃描所有類,包括沒有新增三層註解的類。

3. @Scope

使用這個註解可以給Ioc容器中的bean設定作用域。xml的配置方式可以在標籤的屬性中設定;註解方式可以直接用@Scope來完成;

元件的作用域有四種:
singleton: 單例(預設值) , ioc容器啟動會呼叫方法建立物件;以後每次用會從容器拿(map.get())
prototype: 多例項: ioc啟動時不會去呼叫方法建立,每次需要獲取時才會呼叫方法建立物件;
request : 同一個請求建立一個例項;
session: 同一個session 建立一個例項;

3.1 bean的懶載入

標註@Lazy註解的bean在容器初始化時不會被建立
懶載入只針對單例模式下。預設情況下單例模式在容器啟動的時候就會初始化bean,如果想單例模式下第一次獲取bean時再建立,可以給該bean設為懶載入,使用@Lazy;

4. @Conditional 條件註解

按照一定的條件進行判斷,滿足條件給容器中註冊bean
在這裡插入圖片描述
從原始碼得知,@Conditional註解的值是class型別(該型別集成了Condition)陣列,
編寫條件判斷

public class DogCondition02 implements Condition {

	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// TODO Auto-generated method stub
		return true;
	} 
}

使用條件註解

	@Bean
	@Conditional(DogCondition02.class)
	public Dog dog02() {
		System.out.println("小黃222222出生了.......");
		return new Dog("小黃", 3);
	}

5. 元件匯入

給容器中註冊元件的方式

  1. 包掃描+元件標註註解(@Controller/@Service/@Repository/@Component)-----有侷限性,不能匯入第三方的元件
  2. @Bean 匯入的第三方包裡面的元件
  3. @Import 快速給容器中匯入一個元件
    1. @Import (要匯入到容器中的元件) : 容器中就會自動註冊這個元件,id預設是全類名;
    2. ImportSelector選擇器: 返回需要匯入的陣列的全類名陣列;
    3. ImportBeanDefinitionRegistrar:手動註冊
  4. 使用Spring提供的FactoryBean(工廠bean)
    1. 預設獲取到的是工廠bean呼叫getObject建立的物件
    2. 要獲取工廠bean本身,需要給id前面加&
      在這裡插入圖片描述

5.1 使用選擇器匯入元件

step1:編寫自定義元件選擇器,需要實現ImportSelector介面

//自定義元件選擇器,返回需要匯入的元件陣列
public class MyImportSelector implements ImportSelector{
	/**
	 * 返回值: 匯入到容器中元件全類名
	 * AnnotationMetadata: 當前標註@Import註解的類的所有註解資訊
	 */
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		// TODO Auto-generated method stub
		return new String[] {"com.atguigu.bean.Blue","com.atguigu.bean.Red"};
	} 
}

step2: 用@Import註解匯入元件,示例程式碼中yell.class元件為Import單個匯入,在自定義選擇其中上面倒入了Blue和Red;

@Configuration
//@ComponentScan("com.atguigu")
@Import({MyImportSelector.class,Yell.class})
public class MainConfig {
//	@Bean
//	public Person getPerson() {
//	return	new Person("zhangsan",20);
//	}
}

最終Ioc容器中包含了Blue,Red以及Yell元件;

5.2 ImportBeanDefinitionRegistrar 手動註冊

step1 : 編寫註冊器,需實現ImportBeanDefinitionRegistrar

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * AnnotationMetadata : 當前類的註解資訊
	 * BeanDefinitionRegistry : BeanDefinition註冊類;把所有需要新增到容器中的bean:
	 *      呼叫 void registerBeanDefinition(String beanName, BeanDefinition beanDefinition) 
	 */
	public void registerBeanDefinitions(AnnotationMetadata importingClassMetadata, BeanDefinitionRegistry registry) {
		// 指定bean定義資訊(bean型別,等...)
		RootBeanDefinition beanDefinition = new RootBeanDefinition(Apple.class);
		//註冊一個bean,指定bean名
		registry.registerBeanDefinition("apple", beanDefinition);
	}
}

step 2: 使用@Import時匯入編寫好的註冊器
在這裡插入圖片描述

5.3 使用FactoryBean 註冊元件

step1 : 建立自定義的FactoryBean,實現 FactoryBean介面

//建立一個Spring定義的FactoryBean
public class ColorFactoryBean  implements FactoryBean<Color>{ //泛型為要建立物件的型別
	//返貨一個Color物件,這個物件會新增到容器中
	public Color getObject() throws Exception {
		// TODO Auto-generated method stub
		return new Color();
	}

	public Class<?> getObjectType() {
		// TODO Auto-generated method stub
		return Color.class;
	}
	//建立的物件是不是單例
	public boolean isSingleton() {
		// TODO Auto-generated method stub
		return false;
	}

}

step2 : 在配置中新增bean元件

@Bean
	public  ColorFactoryBean colorFactoryBean() {
		return new ColorFactoryBean();
	}

step3 : 獲取bean
1) 預設獲取到的是工廠bean呼叫getObject建立的物件
2) 要獲取工廠bean本身,需要給id前面加&

@Test
	public void test02() {
		AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(MainConfig.class);
		 Object bean = context.getBean("colorFactoryBean");
		 Object bean02 = context.getBean("&colorFactoryBean");
		 System.out.println("----------->>>"+bean.getClass());
		 System.out.println("----------->>>"+bean02.getClass());
	}

在這裡插入圖片描述

6.元件/bean的生命週期相關注解

bean的生命週期大致分為: bean的建立 >> 初始化 >> 銷燬
執行構造(即物件的建立):
scope=singleton的例項:在容器啟動的時候建立;scope=prototype的例項:在每次獲取的時候建立物件;

6.1 通過指定初始化和銷燬方法來管理bean的建立過程

@Bean註解中的屬性initMethod和destroyMethod設定響應的方法名

  @Bean(initMethod = "init",destroyMethod = "destroy")
    public Car car(){
        return  new Car();
    }
  //*******************
  public class Car {
    public Car() {
        System.out.println("Car()..........");
    }
    public void init(){
        System.out.println("Car ------init()");
    }
    public void destroy(){
        System.out.println("car ---------destroy");
    }
}

6.2 通過bean實現InitializingBean和DisposableBean的方式來管理bean的建立過程

6.3 使用JSR250中的@PostConstructh和@PreDestroy註解來管理

在初始化方法上新增@PostConstruct,在銷燬方法上新增@PreDestroy;

6.4 使用BeanPostProcessor(bean的後置處理器)來管理