1. @Autowired——自动注入
1.1 属性的自动装配
该注解在开发中使用的太多了,就不举例说了,我们只需要知道该注解默认是按照类型去容器中查找对应的组件的,如果找到有多个相同类型的组件,在将属性名作为组件的id去容器中查找。所以,如果有多个相同类型的组件存在的话,属性名就不能随便写了。这时候,如果希望可以根据属性名查找的话,可以加上另一个注解@Qualifier("属性名")来指定需要装配的组件。
注意:自动装配默认一定要将属性赋值好,没有就会报错。如果希望没有赋值好也不会报错的话,该怎么办了?可以在Autowired上加属性required,例如:@Autowired(required = false)
1.2 方法、构造器、参数位置上的自动装配
@Autowired自动装配不仅可以用于属性上,还可以用于方法、构造器和参数上,作用都是一样的,都是将IOC容器中的对象赋值给组件。
例如:
1)标注在方法上:Spring容器创建当前对象,就会调用该方法完成赋值,方法使用的参数,自定义类型的值从IOC容器中获取
2)构造器上:默认情况下,IOC容器启动的时候会调用无参构造器创建对象,然后进行初始化赋值等操作,我们可以在组件中定义一个有参数的构造函数(这时候如果不指定无参构造器,那么该组件中就没有无参构造器了),在构造器上加上注解@Autowired,那么IOC容器在启动的时候,就会调用该有参构造器完成对象的创建与初始化操作。
3)参数上:效果和上两种一样,如果注解位于构造器的参数上,如果只有一个参数,那么可以省略该注解,但是,@Autowired需要位于set方法上,将IOC容器中的对象注入到该组件中,否则,得到的属性值为null。
注意:这三种方式所能达到的效果是一样的,所以,只需要在组件中使用其中一种即可。
1.3 @Bean方法上的@Autowired
我们同样可以在@Bean标注的配置方法上标注@Autowired,用于属性的赋值,例如:
当然,该注解也可以省略,因为只有一个参数。
2. @Resource
JSR250规范定义的注解,默认按照属性名作为组件名称,当然,该注解可以加载指定name的属性值,该注解是JAVA规范,所以功能上要弱与@Autowired,不支持@Primary,也没有required。
3. @Inject
JSR330规范定义的注解,使用该注解需要添加对应的pom坐标
<!-- https://mvnrepository.com/artifact/javax.inject/javax.inject -->
<dependency>
<groupId>javax.inject</groupId>
<artifactId>javax.inject</artifactId>
<version>1</version>
</dependency>
注意:
1. 该注解支持@Primary功能
2. @Primary注解的作用是当容器中有相同类型的组件的时候,使用该注解标注的注解为主要组件,优先使用该注解标注的组件。
4. Aware注入Spring底层组件
自定义组件想要使用Spring容器底层的一些组件(ApplicationContext、BeanFactory等),可以通过实现XXXAware接口,在创建对象的时候,会调用接口规定的方法注入相关组件,Aware会把spring底层一些组件注入到自定义的Bean中,xxxAware实现原理是使用了spring的后置处理器xxxProcessor,后置处理器在前面介绍过,这里不做介绍。
例如:
@Component
public class Red implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware {
private ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// TODO Auto-generated method stub
System.out.println("传入的ioc:"+applicationContext);
this.applicationContext = applicationContext;
}
@Override
public void setBeanName(String name) {
// TODO Auto-generated method stub
System.out.println("当前bean的名字:"+name);
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
// TODO Auto-generated method stub
String resolveStringValue = resolver.resolveStringValue("你好 ${os.name} 我是 #{20*18}");
System.out.println("解析的字符串:"+resolveStringValue);
}
}
5. @Profile
是Spring为我们提供的可以根据当前环境动态的激活和切换一系列Bean(组件)的功能。使用@Profile注解,我们可以在不改变代码的情况下,随意的切换不同的环境
5.1 环境搭建
@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile implements EmbeddedValueResolverAware{
@Value("${db.user}")
private String user;
private StringValueResolver valueResolver;
private String driverClass;
@Bean
public Yellow yellow(){
return new Yellow();
}
@Bean("testDataSource")
public DataSource dataSourceTest(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Bean("devDataSource")
public DataSource dataSourceDev(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/ssm_crud");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Bean("prodDataSource")
public DataSource dataSourceProd(@Value("${db.password}")String pwd) throws Exception{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(pwd);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/scw_0515");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
this.valueResolver = resolver;
driverClass = valueResolver.resolveStringValue("${db.driverClass}");
}
}
注意:这个配置文件,我们一般只使用一种获取值的方式即可,这里使用了三种方式,是为了练习一下前面讲过的内容。
5.2 环境注册
前面准备了三套环境,现在看看如何根据不同的环境使用不同的数据源。
操作步骤:
1)给每一个数据源添加@Profile
注意:加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
2)激活方式:
2.1 使用命令参数
在运行的时候,在JVM参数位置加载 -Dspring.profiles.active="环境参数",例如;
2.2 使用代码方式
这时候,创建IOC容器的时候,不能使用有参构造器了,需要使用无参构造器。
public void test01(){
AnnotationConfigApplicationContext applicationContext =
new AnnotationConfigApplicationContext();
//1、创建一个applicationContext
//2、设置需要激活的环境
applicationContext.getEnvironment().setActiveProfiles("dev");
//3、注册主配置类
applicationContext.register(MainConfigOfProfile.class);
//4、启动刷新容器
applicationContext.refresh();
String[] namesForType = applicationContext.getBeanNamesForType(DataSource.class);
for (String string : namesForType) {
System.out.println(string);
}
Yellow bean = applicationContext.getBean(Yellow.class);
System.out.println(bean);
applicationContext.close();
}
注意:@Profile也可以作用于配置类上,这时候只有运行指定的运行环境,整个配置才能生效