一、概览:三个部分
二、IoC容器相关
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 {
}
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}");
}
}