属性赋值
package jane.bean;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
public class Person
{
/*
* 使用@Value赋值可以写的有:
* 1.基本数值,字符串
* 2.可以写SPEL表达式:#{}
* 3.可以写${},用来取出配置文件或运行环境变量中的值
* 按照之前xml来写配置文件,应该是加载资源文件然后${}来获取值
* <context:property-placeholder location="classpath:person.properties"/>
* 现在也差不多按照之前的步骤
* 在配置类里面加上相应的注解
* @PropertySource(value = {"classpath:person.properties"})
*/
@Value("张三")
private String name;
@Value("#{16+2}")
private Integer age;
@Value("${person.lastname}")
private String lastname;
//省略get和set方法
@Override
public String toString()
{
return "Person [name=" + name + ", age=" + age + ", lastname=" + lastname + "]";
}
public Person(String name, Integer age)
{
super();
this.name = name;
this.age = age;
}
public Person()
{
super();
}
}
配置类
package jane.config;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import jane.bean.Person;
@PropertySource(value = {"classpath:person.properties"})
@Configuration
public class MyConfig4
{
@Bean
public Person person()
{
return new Person();
}
}
自动装配
配置类
package jane.config;
import javax.annotation.Resource;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;
import org.springframework.context.annotation.PropertySource;
import jane.bean.Person;
import jane.dao.BookDao;
/*
* 自动装配:
* 就是spring利用依赖注入(DI),完成对IOC容器中各个组件的依赖关系赋值
* 方法有:
* 1)@Autowired:自动注入
* 1.默认优先按照类型去容器中找对应的组件
* 2.如果按照类型找到多个相同类型的组件,再将属性的名称作为组件的id去容器中查找
* 3.@Qualifier("bookDao2"):使用@Qualifier指定需要装配的组件的id,
* 而不是使用属性名,这个@Qualifier注解写在需要自动装配的属性上
* 4.自动装配默认是一定要将属性赋值完成的,没有就会报错
* 可以使用@Autowired(required = false),这样就不一定要赋值了
* 5.@Primary:让spring进行自动装配的时候,默认使用首选的bean,
* 而且这个注解是标注在bean上面的
* 不过也可以继续使用@Qualifier指定需要装配的bean的名字
* 2)spring还支持使用@Resource(JSR250定义)和Inject(JSR330)(都是java规范的注解)
* @Resource:
* 可以和@Autowired一样实现自动装配功能,默认是按照组件名称进行装配的
* 但是不能支持@Primary和@Autowired(required=false)
* @Inject:
* 需要导入javax.inject的包,和Autowired的功能一样,
* 没有required=false功能,其他的都有
* @Autowired是spring定义的,@Resource,@Inject是java定义的
* AutowiredAnnotationBeanPostProcessor:解析自动装配功能
* 3)@Autowired还可以标注在构造器,参数,方法,属性上面,这样都是从容器中获取参数组件的值
* 1.标注在方法上,spring容器创建当前对象就会调用方法,完成赋值
* 方法里面传入的参数,自定义类型的值就会从ioc容器中获取
* @Bean+方法参数,参数是从容器中获取(这里参数中省略了@Autowired注解)
* 2.标注在构造器上面,构造器需要的组件也是从容器中获取
* 如果组件只有一个有参构造器,那么就只能使用这个构造器进行创建对象
* 这个有参构造器的@Autowired可以省略,参数位置的组件还是可以自动从容器中获取
* 3.标在参数位置
* 4)自定义组件想要使用spring底层的一些组件(比如ApplicationContext,BeanFactory,...)
* 那么就需要自定义组件实现xxxAware接口,这样在创建对象的时候,就会调用接口规定的方法注入相关的组件
* 这样就是把spring底层一些组件注入到自定义的bean之中
* xxxAware接口的功能都是借助xxxProcessor,
* 比如ApplicationContextAware就是借助ApplicationContextAwareProcessor
*/
@PropertySource(value = {"classpath:person.properties"})
@Configuration
@ComponentScan({"jane.dao","jane.service","jane.controller","jane.bean"})
public class MyConfig4
{
@Bean
public Person person()
{
return new Person();
}
@Primary
@Bean("bookDao2")
public BookDao bookDao()
{
BookDao bookDao = new BookDao();
bookDao.setLable("2");
return bookDao;
}
}
bean类
package jane.dao;
import org.springframework.stereotype.Component;
@Component
public class BookDao
{
private String lable="1";
public String getLable()
{
return lable;
}
public void setLable(String lable)
{
this.lable = lable;
}
}
package jane.service;
import javax.annotation.Resource;
import javax.inject.Inject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
import jane.dao.BookDao;
@Service
public class BookService
{
// @Qualifier("bookDao2")
@Autowired(required = false)
// @Resource
// @Inject
private BookDao bookDao;
// @Autowired
public BookService(BookDao bookDao)
{
this.bookDao=bookDao;
System.out.println("BookService有参构造器");
}
// public BookService(@Autowired BookDao bookDao)
// {
// this.bookDao=bookDao;
// System.out.println("BookService有参构造器");
// }
// @Autowired
public void setBookDao(BookDao bookDao)
{
this.bookDao = bookDao;
}
public BookDao getBookDao()
{
return bookDao;
}
@Override
public String toString()
{
return "BookService [bookDao=" + bookDao + "]";
}
}
package jane.controller;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;
import jane.service.BookService;
@Controller
public class BookController
{
@Autowired
private BookService bookService;
}
实现xxxAware接口的bean
package jane.bean;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.BeanNameAware;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.stereotype.Component;
import org.springframework.util.StringValueResolver;
@Component
public class ExampleAware implements ApplicationContextAware,BeanNameAware,EmbeddedValueResolverAware
{
//这个接口是得到IOC容器对象
ApplicationContext applicationContext;
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException
{
this.applicationContext=applicationContext;
System.err.println("传进来的"+applicationContext);
}
//这个是得到当前bean的id
@Override
public void setBeanName(String name)
{
System.err.println("当前bean的名字: "+name);
}
//这个是得到容器的字符串的解析器,能解析${}和#{}之类的值
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver)
{
String resolveStringValue = resolver.resolveStringValue("解析的${os.name},岁数#{10+8}");
System.err.println(resolveStringValue);
}
}
原码查看xxxAware工作原理
首先断点在这里
查看断点的前几部,特别是ApplicationContextAware的地方
这里ApplicationContextAwareProcessor首先判断这个bean是不是实现xxxAware众多接口中的一个
刚好我们符合bean instanceof ApplicationContextAware
然后判断一些权限之类的,最后执行invokeAwareInterfaces(bean);
跟进去invokeAwareInterfaces
发现核心的一句话((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
将bean转成父接口,然后调用父接口的方法,实际使用的是实现类(就是bean)的重载的方法
@Profile环境搭建
配置类
package jane.config;
import javax.sql.DataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;
import com.mchange.v2.c3p0.ComboPooledDataSource;
/*
* Profile:
* spring为我们提供的可以根据当前环境动态地激活和切换一系列组件的功能
* 比如现在的环境:
* 开发环境,测试环境,生产环境
* 数据源对应:(A) (B) (C)
*
* @Profile("")指定该组件在哪一个环境的情况下才能被注册到容器中,
* 如果这个组件没有指定的话,如何环境下都是能注册这个组件的
*
* 如果某个组件加了环境标识,那么只有这个环境被激活的时候才会被注册到容器中
* 默认是使用default环境
*
* @Profile("")如果是写在配置类上面,那么就只有是指定的环境的时候,
* 整个配置类里面的所有配置才能开始生效
*
* 切换环境的方法:
* 1.使用命令行的动态参数,在run configurations里面的Arguments的VM arguments
* 写上参数-Dspring.profiles.active=test
* 2.使用代码的方式:
* 点进AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig5.class);
* 发现有参构造器会直接注册容器并且直接刷新容器
public AnnotationConfigApplicationContext(Class<?>... annotatedClasses)
{
this();
register(annotatedClasses);
refresh();
}
所以我们得使用无参构造器,步骤是:
创建applicationcontext,设置需要激活的环境
注册主配置类,启动刷新容器
AnnotationConfigApplicationContext applicationContext1 = new AnnotationConfigApplicationContext();
applicationContext1.getEnvironment().setActiveProfiles("test","dev");
applicationContext1.register(MyConfig5.class);
applicationContext1.refresh();
*/
@PropertySource("classpath:/db.properties")
@Configuration
public class MyConfig5 implements EmbeddedValueResolverAware
{
@Value("${db.user}")
private String user;
private String driverClass;
private StringValueResolver ValueResolver;
@Profile("test")
@Bean("testDataSource")
public DataSource dataSourceTest(@Value("${db.password}")String password) throws Exception
{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/shop?serverTimezone=GMT%2B8");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Profile("dev")
@Bean("DevDataSource")
public DataSource dataSourceDev(@Value("${db.password}")String password) throws Exception
{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/test?serverTimezone=GMT%2B8");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Profile("prod")
@Bean("ProdDataSource")
public DataSource dataSourceProd(@Value("${db.password}")String password) throws Exception
{
ComboPooledDataSource dataSource = new ComboPooledDataSource();
dataSource.setUser(user);
dataSource.setPassword(password);
dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/work?serverTimezone=GMT%2B8");
dataSource.setDriverClass(driverClass);
return dataSource;
}
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver)
{
this.ValueResolver=resolver;
driverClass = ValueResolver.resolveStringValue("${db.driverClass}");
}
}
测试类
@org.junit.Test
public void test3()
{
// AnnotationConfigApplicationContext applicationContext1 = new AnnotationConfigApplicationContext();
// applicationContext1.getEnvironment().setActiveProfiles("test","dev");
// applicationContext1.register(MyConfig5.class);
// applicationContext1.refresh();
AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MyConfig5.class);
// Map<String, DataSource> beansOfType = applicationContext.getBeansOfType(DataSource.class);
// System.out.println(beansOfType);
String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class);
for (String string : beanNamesForType)
{
System.out.println(string);
}
}
资源文件
db.user=root
db.password=1234
db.driverClass=com.mysql.cj.jdbc.Driver