[笔记迁移][Spring注解驱动]概览及IoC容器相关[1]

版权声明:Collected by Bro_Rabbit only for study https://blog.csdn.net/weixin_38240095/article/details/86473500

一、概览:三个部分

Overview

二、IoC容器相关

ContainerOverview

1. @Configuration & @Bean 向容器注册组件

(1) SE环境下,使用AnnotationConfigApplicationContext加载配置类代替之前ClassPathApplicationContext加载类路径下配置文件启动IoC容器
(2) 使用配置类代替配置文件注册

//使用标注@Configuration的配置类代替之前的配置文件(.xml)
@Configuration	
public class MainConfig {
	
	//使用标注@Bean的方法代替之前在配置文件中声明的子节点<bean ...></bean>
	//返回值的类型即为之前的class属性,方法名默认即为之前的id属性,也可以通过@Bean的name进行指定
	/*该方法的作用相当于
	 * <bean id="person" class="me.zj.bean.Person">
	 * 	<property name="name" value="zhangsan"/>
	 * 	<property name="age" value="22"/>
	 * </bean>
	 */
	@Bean(name="person01")
	public Person person(){
		return new Person("zhangsan",22);
	}
	
}

2. @ComponentScan 自动包扫描组件&指定扫描规则

(1) 使用单个扫描策略

@Configuration
//使用@ComponentScan代替之前在配置文件中声明的包扫描,即<context:component-scan base-package="..."></scan>
//实现对@Controller,@Service,@Repository,@Component自动扫描并加入容器(useDefaultFilters, excludeFilters, includeFilters 都有对应的注解属性)
//excludeFilters/includeFilters => Filter[],Filter又是一个注解
//includeFilters不要忘了指定useDefaultFilters=false
@ComponentScan(value="me.zj",excludeFilters={
		//属性type默认为FilterType.ANNOTATION,属性classes即为排除的具体类型
		@Filter(type=FilterType.ANNOTATION,classes={Controller.class,Service.class})
})
public class MainConfig {
	
	@Bean(name="person01")
	public Person person(){
		return new Person("zhangsan",22);
	}
	
}

(2) 使用多个扫描策略

[1] Java8支持@Repeatable,即可以在一个配置类上标注多个@ComponentScan以使用不同的扫描策略
[2] 非Java8可以使用@ComponentScan达到相同目的(其value属性是一个@ComponentScan的数组)

(3) 枚举类型FilterType说明

枚举常量 规则说明
FilterType.ANNOTATION(最常用的方式) 包含/排除classes指定的“注解”
FilterType.ASSIGNABLE_TYPE 包含/排除classes指定的“类型”
FilterType. ASPECTJ(一般不使用) ASPECTJ表达式方式
FilterType.REGEX 正则表达式方式
FilterType.CUSTOM 自定义规则

(4) FilterType.CUSTOM自定义过滤规则:关键在于implements TypeFilter

public class MyTypeFilter implements TypeFilter{

	/**
	 * @param metadataReader the metadata reader for the target class 读取当前正在扫描的目标类“元信息”
	 * @param metadataReaderFactory a factory for obtaining metadata readers 
	 * 		  for other classes(such as superclasses and interfaces) 获取其他任何类的“元信息” 
	 * @return true=>匹配则放入IoC容器 / false=>不匹配
	 */
	@Override
	public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory)
			throws IOException {
		// 获取当前正在扫描的目标类的“注解 元信息”
		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;
	}

}
@Configuration
//由于扫描的是“根包 me.zj”,所以me.zj及其子包下所有的类都会被扫描,送至自定义规则MyTypeFilter进行匹配过滤以决定是否加入IoC容器
@ComponentScan(value="me.zj",includeFilters={
		@Filter(type=FilterType.CUSTOM,classes={MyTypeFilter.class})
},useDefaultFilters=false)
public class MainConfig {

	@Bean(name="person01")
	public Person person(){...}
	
}

3. @Scope 设置组件作用域

@Configuration
public class MainConfig2 {

	/**
	 * ConfigurableBeanFactory#SCOPE_SINGLETON === singleton,IoC容器启动后立即调用方法创建实例置入容器中,之后每次都将从IoC容器中取出该实例
	 * ConfigurableBeanFactory#SCOPE_PROTOTYPE === prototype,IoC容器启动后并不会调用方法创建实例置入容器,而是每次获取时创建一个新实例返回
	 * WebApplicationContext#SCOPE_REQUEST === request
	 * WebApplicationContext#SCOPE_SESSION === session
	 */
	//@Scope(value=ConfigurableBeanFactory.SCOPE_PROTOTYPE)
	@Scope("prototype")
	@Bean(name="person")
	public Person person(){
		return new Person("lisi",22);
	}
}

4. @Lazy 单实例Bean(Singleton) 的懒加载

5. @Conditional 按照条件注册Bean (since 4.0)

(1) SpringBoot底层大量使用的注解

(2) 关键在于implements Condition即自定义筛选条件

/**
 * 判断是否为windows系统
 * @author Z-Jay
 *
 */
public class WindowsCondition implements Condition{

	/**
	 * @param ConditionContext 判断条件能使用的上下文(环境)
	 * @param AnnotatedTypeMetadata 标注了@Conditional的“类型 元信息”
	 */
	@Override
	public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
		// 1.能够获取到IoC使用的BeanFactory
		ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
		
		// 2. 能够获取到类加载器
		ClassLoader classLoader = context.getClassLoader();
		
		// 3. 能够获取到环境(环境变量、虚拟机变量)
		Environment environment = context.getEnvironment();
		
		// 4. 获取用于"Bean定义"注册的组件(注册、移除、包含...)
		BeanDefinitionRegistry beanDefinitionRegistry = context.getRegistry();
		
		String osName = environment.getProperty("os.name");
		
		if(osName.contains("Windows")){
			return true;
		}
		
		return false;
	}

}
//配置类组件统一设置-> @Conditional({Condition})标注在类上:按照一定的条件进行判断,满足则该类配置的所有Bean才能注册生效,可以在方法上重新指定Condition以覆盖
@Configuration
public class MainConfig2 {

	//需求:根据当前系统是linux还是windows,对bill/linus进行注册 -> 动态获取环境变量 Environment
	//配置类组件单个设置-> @Conditional(value={Condition})标注在方法上:按照一定的条件进行判断,满足则给IoC容器中注册Bean
	@Conditional(value={WindowsCondition.class})
	@Bean(name="bill")
	public Person person(){
		return new Person("Bill Gates",60);
	}
	
	@Conditional(value={LinuxCondition.class})
	@Bean(name="linus")
	public Person person01(){
		return new Person("linus",50);
	}
}

6. @Import 快速导入一个组件至容器

(1) 基本用法

@Configuration
//使用目标类的无参构造器,快速导入目标组件,默认id为目标类的全限名
@Import(value={Color.class,Red.class})
public class MainConfig2 {}

(2) ImportSelector:返回需要导入的组件(implements ImportSelector)全类名数组,SpringBoot底层源码中使用较多

/**
 * 自定义逻辑返回需要导入的组件的全类名(数组)
 * @author Z-Jay
 *
 */
public class MyImportSelector implements ImportSelector {

	//AnnotationMetadata即为当前标注@Import的类的“所有注解”元信息
	//注意:不要返回null(空数组可以),否则底层classNames.length会抛出NullPointerException
	@Override
	public String[] selectImports(AnnotationMetadata metadata) {
		return new String[]{Blue.class.getName(),Yellow.class.getName()};
	}
	
}
@Configuration
@Import(value={Color.class,Red.class,MyImportSelector.class})
public class MainConfig2 {}

(3) ImportBeanDefinitionRegistrar:手工注册(implements ImportBeanDefinitionRegistrar)

public class MyImportBeanDefinitionRegistrar implements ImportBeanDefinitionRegistrar {

	/**
	 * @param AnnotationMetadata:当前标注@Import的类的所有注解信息
	 * @param BeanDefinitionRegistry:为容器中所有组件注册的组件
	 * 		    所有添加到IoC容器中的Bean可以通过BeanDefinitionRegistry.registerBeanDefinition手工注册
	 */
	@Override
	public void registerBeanDefinitions(AnnotationMetadata metadata, BeanDefinitionRegistry definitionRegistry) {
		boolean redExist = definitionRegistry.containsBeanDefinition(Red.class.getName());
		boolean blueExist = definitionRegistry.containsBeanDefinition(Blue.class.getName());
		if(redExist && blueExist){
			definitionRegistry.registerBeanDefinition("rainbow", new RootBeanDefinition(Rainbow.class));
		}
	}

}
@Configuration
@Import(value={Color.class,Red.class,MyImportSelector.class,MyImportBeanDefinitionRegistrar.class})
public class MainConfig2 {}

7.FactoryBean 通过工厂注册

public class ColorFactoryBean implements FactoryBean<Color> {

	// 返回一个Color(泛型T)对象并添加到容器中
	@Override
	public Color getObject() throws Exception {
		return new Color();
	}

	@Override
	public Class<?> getObjectType() {
		return Color.class;
	}
	
	// 作用域Singleton(true) OR Prototype(false)
	@Override
	public boolean isSingleton() {
		return true;
	}

}
@Configuration
public class MainConfig2 {
	// 即使标记@Bean(应该创建ColorFactoryBean实例并注册到IoC容器),但实际上自动调用getObject创建Color对象并注册至容器
	// 如何获取工厂Bean本身? 获取时添加默认前缀&。底层支持BeanFactory.FACTORY_BANE_PREFIX
	@Bean
	public ColorFactoryBean colorFactoryBean(){
		return new ColorFactoryBean();
	}
}

8. Bean的生命周期相关

生命周期:创建->初始化->…->销毁的过程,由容器管理

生命周期 说明
创建 Singleton:在容器启动时创建对象
Prototype:在每次获取时创建对象
BeanPostProcessor#postProcessorBeforeInitialization
初始化 对象创建完成,立即调用初始化方法
BeanPostProcessor#postProcessorAfterInitialization
销毁 Singleton:容器关闭时销毁对象
Prototype:容器不会管理该类Bean(不会调用其销毁方法)

(1)@Bean指定自定义的初始化和销毁方法,与配置文件中的init-method / destroy-method 等价

(2) 让Bean实现Initialzingbean接口 / DisposableBean接口,重写afterPropertySet()及destroy()自定义初始化 / 销毁

public class Cat implements InitializingBean,DisposableBean{

	public Cat() {
		System.out.println("Create a cat...");
	}

	/**
	 * Invoked by a BeanFactory on destruction of a singleton.
	 * @throws Exception in case of shutdown errors.
	 * Exceptions will get logged but not rethrown to allow
	 * other beans to release their resources too.
	 */
	@Override
	public void destroy() throws Exception {
		System.out.println("Cat#destory() is called now...");
	}
	
	/**
	 * Invoked by a BeanFactory after it has set all bean properties supplied
	 * (and satisfied BeanFactoryAware and ApplicationContextAware).
	 * <p>This method allows the bean instance to perform initialization only
	 * possible when all bean properties have been set and to throw an
	 * exception in the event of misconfiguration.
	 * @throws Exception in the event of misconfiguration (such
	 * as failure to set an essential property) or if initialization fails.
	 */
	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("Cat has initialized...");
	}

}

(3) JSR250规范注解(标注在方法上)

[1] @PostConstruct:在Bean创建完成之后执行初始化方法
[2] @PreDestroy:在Bean移除容器之前执行销毁方法

@Component
public class Dog {

	public Dog() {
		System.out.println("Create a dog...");
	}
	
	@PostConstruct
	public void init(){
		System.out.println("PostConstruct is called...");
	}

	@PreDestroy
	public void destroy(){
		System.out.println("PreDestory is called...");
	}
}

(4) BeanPostProcessor 后置处理器,在Bean初始化前后 执行一些工作

//将后置处理器加入至IoC容器中
@Component
public class MyBeanPostProcessor implements BeanPostProcessor{

	/**
	 * Apply this BeanPostProcessor to the given new bean instance <i>after</i> any bean
	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
	 * or a custom init-method). The bean will already be populated with property values.
	 * The returned bean instance may be a wrapper around the original.
	 * <p>In case of a FactoryBean, this callback will be invoked for both the FactoryBean
	 * instance and the objects created by the FactoryBean (as of Spring 2.0). The
	 * post-processor can decide whether to apply to either the FactoryBean or created
	 * objects or both through corresponding {@code bean instanceof FactoryBean} checks.
	 * <p>This callback will also be invoked after a short-circuiting triggered by a
	 * {@link InstantiationAwareBeanPostProcessor#postProcessBeforeInstantiation} method,
	 * in contrast to all other BeanPostProcessor callbacks.
	 * @param bean the new bean instance
	 * @param beanName the name of the bean
	 * @return the bean instance to use, either the original or a wrapped one;
	 * if {@code null}, no subsequent BeanPostProcessors will be invoked
	 * @throws org.springframework.beans.BeansException in case of errors
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
	 * @see org.springframework.beans.factory.FactoryBean
	 */
	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("MyBeanPostProcessor#postProcessAfterInitialization is called ===>"+beanName);
		return bean;
	}

	/**
	 * Apply this BeanPostProcessor to the given new bean instance <i>before</i> any bean
	 * initialization callbacks (like InitializingBean's {@code afterPropertiesSet}
	 * or a custom init-method). The bean will already be populated with property values.
	 * The returned bean instance may be a wrapper around the original.
	 * @param bean the new bean instance
	 * @param beanName the name of the bean
	 * @return the bean instance to use, either the original or a wrapped one;
	 * if {@code null}, no subsequent BeanPostProcessors will be invoked
	 * @throws org.springframework.beans.BeansException in case of errors
	 * @see org.springframework.beans.factory.InitializingBean#afterPropertiesSet
	 */
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		System.out.println("MyBeanPostProcessor#postProcessBeforeInitialization is called ===>"+beanName);
		return bean;
	}

}

[1] 底层源码

//org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory

//以下的一段过程都是在AbstractApplicationContext#refresh()--->AbstractApplicationContext#finishBeanFactoryInitialization(ConfigurableListableBeanFactory)->DefaultListenableBeanFactory#preInstantiateSingletonsdoGetBean()->AbstractBeanFactory#doGetBean(final String, final Class<T>, final Object[], boolean)->AbstractAutowireCapableBeanFactory#doCreateBean(final String, final RootBeanDefinition, final Object[])->AbstractAutowireCapableBeanFactory#populateBean(beanName, mbd, instanceWrapper)给属性赋值后执行

protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
  	//... ...
	if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
		}

		try {
			invokeInitMethods(beanName, wrappedBean, mbd);
		}
		catch (Throwable ex) {
			throw new BeanCreationException(
					(mbd != null ? mbd.getResourceDescription() : null),
					beanName, "Invocation of init method failed", ex);
		}

		if (mbd == null || !mbd.isSynthetic()) {
			wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
		}
  //... ...
}

//applyBeanPostProcessorsBeforeInitializationy与applyBeanPostProcessorsAfterInitialization逻辑一样
	@Override
	public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
			throws BeansException {

		Object result = existingBean;
      	//遍历容器中所有的BeanPostProcessor,依次执行postProcessBeforeInitialization()
		for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
			result = beanProcessor.postProcessBeforeInitialization(result, beanName);
          	//一旦返回为null(No original or wrapped one),其后的BeanPostProcessor都不会被调用,直接返回跳出
			if (result == null) {
				return result;
			}
		}
		return result;
	}

[2] Spring底层对BeanPostProcessor的使用非常多,ApplicationContextAwareProcessor、BeanValidationPostProcessor、InitDestroyAnnotationBeanPostProcessor、AutowiredAnnotationBeanPostProcessor等

package org.springframework.context.support;

import java.security.AccessControlContext;
import java.security.AccessController;
import java.security.PrivilegedAction;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.Aware;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.beans.factory.config.EmbeddedValueResolver;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.ApplicationEventPublisherAware;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.EnvironmentAware;
import org.springframework.context.MessageSourceAware;
import org.springframework.context.ResourceLoaderAware;
import org.springframework.util.StringValueResolver;

/**
 * {@link org.springframework.beans.factory.config.BeanPostProcessor}
 * implementation that passes the ApplicationContext to beans that
 * implement the {@link EnvironmentAware}, {@link EmbeddedValueResolverAware},
 * {@link ResourceLoaderAware}, {@link ApplicationEventPublisherAware},
 * {@link MessageSourceAware} and/or {@link ApplicationContextAware} interfaces.
 *
 * <p>Implemented interfaces are satisfied in order of their mention above.
 *
 * <p>Application contexts will automatically register this with their
 * underlying bean factory. Applications do not use this directly.
 *
 * @author Juergen Hoeller
 * @author Costin Leau
 * @author Chris Beams
 * @since 10.10.2003
 * @see org.springframework.context.EnvironmentAware
 * @see org.springframework.context.EmbeddedValueResolverAware
 * @see org.springframework.context.ResourceLoaderAware
 * @see org.springframework.context.ApplicationEventPublisherAware
 * @see org.springframework.context.MessageSourceAware
 * @see org.springframework.context.ApplicationContextAware
 * @see org.springframework.context.support.AbstractApplicationContext#refresh()
 */
class ApplicationContextAwareProcessor implements BeanPostProcessor {

	private final ConfigurableApplicationContext applicationContext;

	private final StringValueResolver embeddedValueResolver;
  	/**
  	 *Create a new ApplicationContextAwareProcessor for the given context.
  	 */
    public ApplicationContextAwareProcessor(ConfigurableApplicationContext applicationContext) {
      this.applicationContext = applicationContext;
      this.embeddedValueResolver = new EmbeddedValueResolver(applicationContext.getBeanFactory());
  }
  
    @Override
   	public Object postProcessBeforeInitialization(final Object bean, String beanName) throws BeansException {

   		AccessControlContext acc = null;

   		if (System.getSecurityManager() != null &&

   				(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||

   						bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||

   						bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)) {

   			acc = this.applicationContext.getBeanFactory().getAccessControlContext();

   		}

   		if (acc != null) {

   			AccessController.doPrivileged(new PrivilegedAction<Object>() {

   				@Override

   				public Object run() {

   					invokeAwareInterfaces(bean);

   					return null;

   				}

   			}, acc);

   		}

   		else {

   			invokeAwareInterfaces(bean);

   		}

   		return bean;

   	}

   	private void invokeAwareInterfaces(Object bean) {

   		if (bean instanceof Aware) {

   			if (bean instanceof EnvironmentAware) {

   				((EnvironmentAware) bean).setEnvironment(this.applicationContext.getEnvironment());

   			}

   			if (bean instanceof EmbeddedValueResolverAware) {

   				((EmbeddedValueResolverAware) bean).setEmbeddedValueResolver(this.embeddedValueResolver);

   			}

   			if (bean instanceof ResourceLoaderAware) {

   				((ResourceLoaderAware) bean).setResourceLoader(this.applicationContext);

   			}

   			if (bean instanceof ApplicationEventPublisherAware) {

   				((ApplicationEventPublisherAware) bean).setApplicationEventPublisher(this.applicationContext);

   			}

   			if (bean instanceof MessageSourceAware) {

   				((MessageSourceAware) bean).setMessageSource(this.applicationContext);

   			}

   			if (bean instanceof ApplicationContextAware) {

   				((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);

   			}

   		}

   	}

   	@Override
   	public Object postProcessAfterInitialization(Object bean, String beanName) {

   		return bean;

   	}

   }

9. @Value 组件赋值

三种赋值形式:
(1) 基本数值
(2) SpEL: #{…}
(3) 读取配置文件中的值(运行时变量中的值):${…}【需要之前使用@PropertySource加载properties文件】

public class Person {

  //等价于之前配置文件<property class="..." value="..."></property>
	@Value("张三")
	private String name;
	
	@Value("#{2*11}")
	private Integer age;
	
	@Value("${person.nickName}")
	private String nickName;


	//JavaBean其他代码...
}

10. @PropertySource 加载外部配置文件

@Configuration
//@PropertySource读取外部配置文件中的k/v键值对保存到环境变量Enviroment中,之后可以使用${}取出配置文件中的值
//相当于之前配置文件中<context:property-placeholder location="..."/>
@PropertySource(value={"classpath:/me/zj/resources/person.properties"},encoding="UTF-8")
public class MainConfigOfPropertyValues {

	@Bean
	public Person person(){
		return new Person();
	}
	
}

11. @Autowired+@Qualifier、 @Primary、@Resource(JSR250规范,非Spring)、@Inject(JSR330规范,非Spring) 自动装配

【@Autowired+@Qualifier、@Resource(JSR250其用法用途不再赘述)】

(1) 使用@Primary,指定Spring在自动装配该类型Bean时的“默认首选项”,可以使用@Qualifier显式指定以覆盖

@Configuration
public class MainConfigOfPropertyValues {

  	@Bean
	public Person person(){
		return new Person();
	}
  
	@Primary
	@Bean(name="person2")
	public Person person(){
		return new Person();
	}
	
}

(2) @Inject(JSR330)与@Autowired功能一样,但使用前需要导入依赖

<dependency>
    <groupId>javax.inject</groupId>
    <artifactId>javax.inject</artifactId>
    <version>1</version>
</dependency>

(3) 标注@Autowired至其他位置

注意:不论置于何处,都将从容器中获取对应类型的组件注入

位置 说明
方法METHOD IoC容器创建当前类的对象时将调用被标注@Autowired的方法,不仅限setter
方法使用的参数,自定义类型将从IoC容器中取值注入
构造器CONSTRUCTER 默认情况下,IoC容器调用Bean的无参构造器创建对象
若在有参构造器上标注@Autowired,IoC容器将调用该构造器创建对象,其使用的参数同样从IoC容器中取值注入
若该Bean只有一个有参构造器(无参构造器被覆盖),@Autowired可以省略
参数PARAM 效果与以上两种情况一致
最常用的是在配置类中使用@Bean注入组件时,参数从容器中获取,默认省略@Autowired

(4) 实现Aware接口以注入Spring底层组件(如ApplicationContext, BeanFactory, xxx)

只要让自定义类型implements xxxAware即可。 创建对象时会调用接口规定方法以注入相关组件

/**
 * Marker superinterface indicating that a bean is eligible to be
 * notified by the Spring container of a particular framework object
 * through a callback-style method. Actual method signature is
 * determined by individual subinterfaces, but should typically
 * consist of just one void-returning method that accepts a single
 * argument.
 *
 * <p>Note that merely implementing {@link Aware} provides no default
 * functionality. Rather, processing must be done explicitly, for example
 * in a {@link org.springframework.beans.factory.config.BeanPostProcessor BeanPostProcessor}.
 * Refer to {@link org.springframework.context.support.ApplicationContextAwareProcessor}
 * and {@link org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory}
 * for examples of processing {@code *Aware} interface callbacks.
 *
 * @author Chris Beams
 * @since 3.1
 */
public interface Aware {

}

AwareInterfaces
xxxAware的功能是通过与其对应的xxxProcessor实现的,如ApplicationContextAware===>ApplicationContextAwareProcessor(原理)

12. @Profile 根据当前环境动态激活切换一系列组件

//以切换c3p0数据源为例
@Configuration
@PropertySource("classpath:/me/zj/resources/dbConfig.properties")
/*
 * @Profile 标识组件在哪个环境下才能被注册到容器中(环境标识符是任意的),若不指定则任何环境下都能注册该组件
 * (1)添加环境标识的Bean,只有在该环境激活时才能注册到IoC容器中,默认环境标识为default(与不指定的情况一致)
 * (2)如何切换环境
 * 	[1] 使用命令行动态参数即Run Configuration->arguments->VM arguments, -Dspring.profiles.active={某环境标识}
 * 	[2] 使用代码实现,参照AnnotationApplicationContext有参构造函数,在第一步this()和第二步register(MainClass)插入一步applicationContext.getEnvironment().setActiveProfiles(...)
 */
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
	
	//使用.properties配置文件的两种方式
	//第一种:@Value注入至字段
	@Value("${db.user}")
	private String user;
	
	//第二种:@Value注入至参数
	
	//第三种:implements EmbeddedValueResolverAware
	private StringValueResolver valueResolver;
	
	private String driverClass;
	
	@Profile({"test"})
	@Bean(name="testDataSource")
	public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws PropertyVetoException{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(pwd);
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ioc");
		dataSource.setDriverClass(driverClass);
		return dataSource;
	}
	
	@Profile("dev")
	@Bean(name="devDataSource")
	public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws PropertyVetoException{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(pwd);
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/muke");
		dataSource.setDriverClass(driverClass);
		return dataSource;
	}
	
	@Profile("pro")
	@Bean(name="proDataSource")
	public DataSource dataSourcePro(@Value("${db.password}")String pwd) throws PropertyVetoException{
		ComboPooledDataSource dataSource = new ComboPooledDataSource();
		dataSource.setUser(user);
		dataSource.setPassword(pwd);
		dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/teaching_system");
		dataSource.setDriverClass(driverClass);
		return dataSource;
	}

	// 使用Spring底层字符串解析器读取解析后设置
	@Override
	public void setEmbeddedValueResolver(StringValueResolver stringValueResolver) {
		this.valueResolver = stringValueResolver;
		driverClass = valueResolver.resolveStringValue("${db.driverClass}");
	}
	
}

猜你喜欢

转载自blog.csdn.net/weixin_38240095/article/details/86473500