天天看點

Spring注解驅動開發(一)一、元件注冊二、生命周期三、屬性指派四、自動裝配

目錄

一、元件注冊

@Configuration

@Bean

@ComponentScan

@Scope

@Lazy

@Conditional

@import

FactoryBean

二、生命周期

@Bean指定初始化和銷毀方法

實作InitializingBean和DisposableBean接口

JSR250

BeanPostProcessor(bean的後置處理器)

總結

三、屬性指派

@PropertySource

@Value

四、自動裝配

@Autowired

@Qualifier

@Primary

一、元件注冊

@Configuration

作用:告訴Spring這是一個配置類
@Configuration  //告訴Spring這是一個配置類
public class MainConfig {}
           

@Bean

作用:給容器中注冊一個Bean;類型為傳回值的類型,id預設是用方法名作為id,也可以通過value屬性設定id
@Configuration  //告訴Spring這是一個配置類
public class MainConfig {
	//給容器中注冊一個Bean;類型為傳回值的類型,id預設是用方法名作為id
	@Bean("person")
	public Person person01(){
		return new Person("lisi", 20);
	}
}
           

@ComponentScan

作用:開啟元件掃描

參數:

value:指定要掃描的包

excludeFilters = Filter[] :指定掃描的時候按照什麼規則排除那些元件

includeFilters = Filter[] :指定掃描的時候隻需要包含哪些元件

FilterType.ANNOTATION:按照注解類型過濾

FilterType.ASSIGNABLE_TYPE:按照給定的類型過濾

FilterType.ASPECTJ:使用ASPECTJ表達式過濾

FilterType.REGEX:使用正規表達式過濾

FilterType.CUSTOM:使用自定義規則過濾

@Configuration  //告訴Spring這是一個配置類
@ComponentScans(
		value = {
				@ComponentScan(value="com.atguigu",includeFilters = {
/*						@Filter(type=FilterType.ANNOTATION,classes={Controller.class}),
						@Filter(type=FilterType.ASSIGNABLE_TYPE,classes={BookService.class}),*/
						@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
				},useDefaultFilters = false)	
		}
		)
public class MainConfig {
	@Bean("person")
	public Person person01(){
		return new Person("lisi", 20);
	}

}
           

自定義規則

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;
	}

}
           

@Scope

作用:調整JavaBean的作用域

參數:

prototype:多執行個體的:ioc容器啟動并不會去調用方法建立對象放在容器中。(每次擷取的時候才會調用方法建立對象)

singleton:單執行個體的(預設值):ioc容器啟動會調用方法建立對象放到ioc容器中。(以後每次擷取就是直接從容器map.get()中拿)

request:同一次請求建立一個執行個體

session:同一個session建立一個執行個體

@Scope("prototype")
	@Bean("person")
	public Person person(){
		System.out.println("給容器中添加Person....");
		return new Person("張三", 25);
	}
           

@Lazy

作用:懶加載

說明:

單執行個體bean會預設在容器啟動的時候建立對象,懶加載即在容器啟動時不建立對象。第一次使用(擷取)Bean建立對象,并初始化;

@Lazy
	@Bean("person")
	public Person person(){
		System.out.println("給容器中添加Person....");
		return new Person("張三", 25);
	}
           

@Conditional

作用:按照一定的條件進行判斷,滿足條件給容器中注冊bean

示例:

(1)如果系統是windows,給容器中注冊("bill")

(2)如果是linux系統,給容器中注冊("linus")

判定條件(Linux)

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

	/**
	 * ConditionContext:判斷條件能使用的上下文(環境)
	 * AnnotatedTypeMetadata:注釋資訊
	 */
	@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定義的注冊類
		BeanDefinitionRegistry registry = context.getRegistry();
		
		String property = environment.getProperty("os.name");
		
		//可以判斷容器中的bean注冊情況,也可以給容器中注冊bean
		boolean definition = registry.containsBeanDefinition("person");
		if(property.contains("linux")){
			return true;
		}
		
		return false;
	}

}
           

 判斷條件(Windows)

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

	@Override
	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;
	}

}
           

注解使用示例 

@Conditional(WindowsCondition.class)
    @Bean("bill")
	public Person person01(){
		return new Person("Bill Gates",62);
	}
	
	@Conditional(LinuxCondition.class)
	@Bean("linus")
	public Person person02(){
		return new Person("linus", 48);
	}
           

@import

作用:快速給容器中導入一個元件

方式:

1)@Import(要導入到容器中的元件);容器中就會自動注冊這個元件,id預設是全類名

2)ImportSelector:傳回需要導入的元件的全類名數組;

3)ImportBeanDefinitionRegistrar:手動注冊bean到容器中

 實作ImportSelector接口

//自定義邏輯傳回需要導入的元件
public class MyImportSelector implements ImportSelector {

	//傳回值,就是到導入到容器中的元件全類名
	//AnnotationMetadata:目前标注@Import注解的類的所有注解資訊
	@Override
	public String[] selectImports(AnnotationMetadata importingClassMetadata) {
		//方法不要傳回null值
		return new String[]{"com.atguigu.bean.Blue","com.atguigu.bean.Yellow"};
	}

}
           

 實作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.atguigu.bean.Red");
		boolean definition2 = registry.containsBeanDefinition("com.atguigu.bean.Blue");
		if(definition && definition2){
			//指定Bean定義資訊;(Bean的類型,Bean。。。)
			RootBeanDefinition beanDefinition = new RootBeanDefinition(RainBow.class);
			//注冊一個Bean,指定bean名
			registry.registerBeanDefinition("rainBow", beanDefinition);
		}
	}
}
           

注解使用示例 

//類中元件統一設定。滿足目前條件,這個類中配置的所有bean注冊才能生效;
@Conditional({WindowsCondition.class})
@Configuration
@Import({Color.class,Red.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
public class MainConfig2 {}
           

FactoryBean

作用:使用Spring提供的 FactoryBean(工廠Bean)

特點:

1)、預設擷取到的是工廠bean調用getObject建立的對象

2)、要擷取工廠Bean本身,我們需要給id前面加一個& (&colorFactoryBean)

Object bean4 = applicationContext.getBean("&colorFactoryBean");
           

實作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指定初始化和銷毀方法

說明:通過@Bean指定init-method和destroy-method

Car.class

@Component
public class Car {
	
	public Car(){
		System.out.println("car constructor...");
	}
	
	public void init(){
		System.out.println("car ... init...");
	}
	
	public void detory(){
		System.out.println("car ... detory...");
	}

}
           
@Bean(initMethod="init",destroyMethod="detory")
	public Car car(){
		return new Car();
	}
           

實作InitializingBean和DisposableBean接口

說明:通過讓Bean實作InitializingBean(定義初始化邏輯);DisposableBean(定義銷毀邏輯)。
@Component
public class Cat implements InitializingBean,DisposableBean {
	
	public Cat(){
		System.out.println("cat constructor...");
	}

	@Override
	public void destroy() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("cat...destroy...");
	}

	@Override
	public void afterPropertiesSet() throws Exception {
		// TODO Auto-generated method stub
		System.out.println("cat...afterPropertiesSet...");
	}

}
           

JSR250

說明:

@PostConstruct:在bean建立完成并且屬性指派完成;來執行初始化方法

@PreDestroy:在容器銷毀bean之前通知我們進行清理工作

@Component
public class Dog implements ApplicationContextAware {
	
	public Dog(){
		System.out.println("dog constructor...");
	}
	
	//對象建立并指派之後調用
	@PostConstruct
	public void init(){
		System.out.println("[email protected]...");
	}
	
	//容器移除對象之前
	@PreDestroy
	public void detory(){
		System.out.println("[email protected]...");
	}
}
           

BeanPostProcessor(bean的後置處理器)

說明:在bean初始化前後進行一些處理工作。

postProcessBeforeInitialization:在初始化之前工作

postProcessAfterInitialization:在初始化之後工作

/**
 * 後置處理器:初始化前後進行處理工作
 * 将後置處理器加入到容器中
 * @author lfy
 */
@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;
	}

}
           

總結

1.關于初始化和銷毀

(1)初始化:對象建立完成,并指派好,調用初始化方法。。。

(2)銷毀:單執行個體:容器關閉的時候;多執行個體:容器不會管理這個bean;容器不會調用銷毀方法;

2.BeanPostProcessor原理

第一步

(1)populateBean(beanName, mbd, instanceWrapper);給bean進行屬性指派

第二步

(2)initializeBean(調用初始化方法)

(2.1)applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);在初始化之前執行

(2.2)invokeInitMethods(beanName, wrappedBean, mbd);執行自定義初始化

(2.3)applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);在初始化之後執行

3.Spring底層對 BeanPostProcessor 的使用

(1)bean指派,注入其他元件

(2)@Autowired,生命周期注解功能

(3)@Async,xxx BeanPostProcessor;

三、屬性指派

@PropertySource

說明:使用@PropertySource讀取外部配置檔案中的k/v儲存到運作的環境變量中;加載完外部的配置檔案以後使用${}取出配置檔案的值

 person.properties配置檔案

person.nickName=小張三
           

配置類中引入配置檔案 

@PropertySource(value={"classpath:/person.properties"})
@Configuration
public class MainConfigOfPropertyValues {
	
	@Bean
	public Person person(){
		return new Person();
	}

}
           

@Value

可以指派的類型:

1、基本數值

2、可以寫SpEL; #{}

3、可以寫${};取出配置檔案【properties】中的值(在運作環境變量裡面的值)

public class Person {

	@Value("張三")
	private String name;
	@Value("#{20-2}")
	private Integer age;
	
	@Value("${person.nickName}")
	private String nickName;
	
	public String getNickName() {
		return nickName;
	}
	public void setNickName(String nickName) {
		this.nickName = nickName;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public Integer getAge() {
		return age;
	}
	public void setAge(Integer age) {
		this.age = age;
	}
	
	public Person(String name, Integer age) {
		super();
		this.name = name;
		this.age = age;
	}
	public Person() {
		super();
		// TODO Auto-generated constructor stub
	}
	@Override
	public String toString() {
		return "Person [name=" + name + ", age=" + age + ", nickName=" + nickName + "]";
	}

}
           

四、自動裝配

@Autowired

特點:

(1)預設優先按照類型去容器中找對應的元件:applicationContext.getBean(BookDao.class);找到就指派

(2)如果找到多個相同類型的元件,再将屬性的名稱作為元件的id去容器中查找applicationContext.getBean("bookDao")

(3)可以使用@Autowired(required=false),允許找不到對應的JavaBean對象。

示例:如下有兩個BookDao的實作類,自動裝配預設會去綁定屬性名稱相同的實作類,即bookDao,而不是bookDao2

@Configuration
@ComponentScan({"com.atguigu.service","com.atguigu.dao",
	"com.atguigu.controller","com.atguigu.bean"})
public class MainConifgOfAutowired {
	
	@Bean("bookDao2")
	public BookDao bookDao(){
		BookDao bookDao = new BookDao();
		bookDao.setLable("2");
		return bookDao;
	}	
}
           
@Repository
public class BookDao {
	
	private String lable = "1";

	public String getLable() {
		return lable;
	}

	public void setLable(String lable) {
		this.lable = lable;
	}

	@Override
	public String toString() {
		return "BookDao [lable=" + lable + "]";
	}

}
           
@Service
public class BookService {
	
	@Autowired(required=false)
	private BookDao bookDao;
	
	public void print(){
		System.out.println(bookDao);
	}

	@Override
	public String toString() {
		return "BookService [bookDao=" + bookDao + "]";
	}
}
           

@Qualifier

作用:使用@Qualifier指定需要裝配的元件的id,而不是使用屬性名

示例:如下代碼,自動裝配的是bookDao而不是bookDao2

@Service
public class BookService {
	
	@Qualifier("bookDao")
	@Autowired()
	private BookDao bookDao2;
	
	public void print(){
		System.out.println(bookDao);
	}

	@Override
	public String toString() {
		return "BookService [bookDao=" + bookDao + "]";
	}	
}
           

@Primary

作用:讓Spring進行自動裝配的時候,預設使用首選的bean;也可以繼續使用@Qualifier指定需要裝配的bean的名字
@Configuration
@ComponentScan({"com.atguigu.service","com.atguigu.dao",
	"com.atguigu.controller","com.atguigu.bean"})
public class MainConifgOfAutowired {
	
	@Primary
	@Bean("bookDao2")
	public BookDao bookDao(){
		BookDao bookDao = new BookDao();
		bookDao.setLable("2");
		return bookDao;
	}
}
           

未完待續~~~~