目录
3.1:自定义初始化和销毁方法,在容器对bean进行生命周期处理的时候调用我们自己的初始化,销毁方法
3.2:实现implements InitializingBean, DisposableBean接口来初始化和销毁bean对象
5.@PropertySource加载配置属性源,然后使用@value设置数据
看到有和我一样看了该视频总结的博友,喜欢的可以去看看
1.@scope
singleton:单例模式,ioc容器创建的时候就会调用这个方法创建对象放在容器中,下次获取就是从容器中直接获取
单例模式也可以实现不在ioc容易启动的时候创建bean,使用@Lzay实现懒加载,也可以在获取的时候创建对象,且仅仅会创建一次,不管你获取几次,并且获取几次的bean都是一样的,区别于多例模式每次获取每次都创建,多次获取的bean不相同.
prototype:多例模式,ioc容器启动不会创建,获取的时候才会创建出来,而且没每次获取都会创建,所以每次获取的对象不相同.
2.@conditional注解,分条件加载bean
linux的同样写法,条件不一样而已,这只是简单的演示,context中还能获取其他组件能帮助根据条件加载bean.如果@conditional加在类上面就是整个类的配置都生效.
总结:给容器中注册组件:
1:包扫描+组件标注注解(@Controller,@Service,@Repository,@Component)
2.使用@Bean,写在方法上,返回一个组件对象
3.@Import({多个需要导入了大类}) 写在类上面,id默认是全类名
4.@Import配合ImportSelector来注册bean
4.1.使用@Import引入我们自定义的MyImportSelector,例如:@Import({MyImportSelector.class})
4.2. 定义MyImportSelector,实现ImportSelector,实现里面的selectImports方法,方法返回一个String数组,数组里面就是我们要导入的类的全类名.例如:return new String[]{"com.alimm.model.Apple","com.alimm.model.Pear"},这样就能注册到spring中.
5.使用ImportDefinitionRegistrar,实现registerBeanDefinitions方法,
6. 使用FctoryBean来注册bean对象
package com.honeypeng.factory;
import com.honeypeng.entity.Employee;
import org.springframework.beans.factory.FactoryBean;
public class MyFactory implements FactoryBean<Employee> {
//获取到某个bean
@Override
public Employee getObject() throws Exception {
return new Employee();
}
//获取到bean类型
@Override
public Class<?> getObjectType() {
return Employee.class;
}
//是否单例
@Override
public boolean isSingleton() {
return true;
}
}
3.bean的生命周期
3.1:自定义初始化和销毁方法,在容器对bean进行生命周期处理的时候调用我们自己的初始化,销毁方法
2.1.1:如果是配置文件的方式,我们就需要在<Bean>配置中加上 init-method和destory-method
2.1.2:如果是使用注解@Bean的方式也一样使用 @Bean(initMethod = "init",destroyMethod = "destory"),init和destory就是在bean对象中我们自己定义的初始化和销毁方法.
@Bean(initMethod = "init",destroyMethod = "destory")
public Employee employee(){
return new Employee();
}
如果是单实例bean,容器会在启动的时候创建,初始化,然后容器关闭的时候销毁 application.close()的时候关闭.
如果是多实例bean,会在获取的时候创建bean,并且初始化,但是不会帮忙销毁bean.
3.2:实现implements InitializingBean, DisposableBean接口来初始化和销毁bean对象
package com.honeypeng.bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
/**
* Created by jx on 2018/9/16.
*/
public class Pig implements InitializingBean, DisposableBean {
private String name;
private Integer Age;
public Pig(){
System.out.println(this.getClass().getName()+" Constructor ");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return Age;
}
public void setAge(Integer age) {
Age = age;
}
private void init() {
System.out.println(this.getClass().getName() + " +++++init()...");
}
private void destory() {
System.out.println(this.getClass().getName() + " +++++destory()");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(this.getClass().getName() + " +++++afterPropertiesSet....");
}
@Override
public void destroy() throws Exception {
System.out.println(this.getClass() + " +++++destroy...");
}
@PostConstruct
public void postConstruct() {
System.out.println(this.getClass().getName()+" +++++postConstruct");
}
}
从这里可以看出执行顺序是: 构造方法(设置好值后)>@PostConstruct> initializingBean的afterPropertiesSet方法 > bean对象中自己定义的init()初始化方法.(使用@Bean(initMethod = "init",destroyMethod = "destory"))
顺序如下:Constructor > @PostConstruct > InitializingBean > init-method
然后bean的销毁先后顺序是:disposableBean的Destory方法>> 自定义的destory方法(@Bean(initMethod = "init",destroyMethod = "destory")
)
3.3:使用JSR250规范中的两个注解
@PostConstract(在bean创建完之后且属性赋值完成,来执行该方法)
@PreDstory(在容器销毁bean对象之前执行该方法)
package com.honeypeng.bean;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
/**
* Created by jx on 2018/9/16.
*/
public class Pig implements InitializingBean, DisposableBean {
private String name;
private Integer Age;
public Pig(){
System.out.println(this.getClass().getName()+" Constructor ");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return Age;
}
public void setAge(Integer age) {
Age = age;
}
private void init() {
System.out.println(this.getClass().getName() + " +++++init()...");
}
private void destory() {
System.out.println(this.getClass().getName() + " +++++自定义的destory()");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println(this.getClass().getName() + " +++++afterPropertiesSet....");
}
@Override
public void destroy() throws Exception {
System.out.println(this.getClass() + " +++++ DisposableBean.destroy...");
}
@PostConstruct
public void postConstruct() {
System.out.println(this.getClass().getName()+" +++++postConstruct");
}
@PreDestroy
public void preDestory() {
System.out.println(this.getClass().getName()+" +++++preDestory");
}
}
执行结果是:
可以看得出来顺序是 preDestory>>disposableBean的distory方法>>自定义的destory方法
3.4:使用BeanPostProcessor
postProcessBeforeInitialization:在属性赋值和所有的初始化操作之前,无论是@PostConstruct > InitializingBean > init-method中的任何一个初始化方法之前执行
postProcessAfterInitialization:在所有的初始化操作之后执行,无论是@PostConstruct > InitializingBean > init-method中的任何一个之后执行.
4.spring的@value注解
可以使用@value设置属性值,通常有下面三种使用方法
4.1:括号中写具体的数值
比如:@Value("张三")
4.2:使用SpEL表达式
@Value("#{20/2}")
4.3:使用$符号
@Value("${配置文件中配置的数值}")
5.@PropertySource加载配置属性源,然后使用@value设置数据
6.@ConfigurationProperties
当我们需要直接将配置文件中的数据映射设置到自己建好的对象中,就可以使用这个注解,@ConfigurationProperties(prefix = "person")
配置文件:
person:
lastName: hello
age: 18
boss: false
birth: 2017/12/12
maps: {k1: v1,k2: 12}
lists:
- lisi
- zhaoliu
dog:
name: 小狗
age: 12
7.自动注入
7.1:@Autowired--spring注解
现根据类型注入,如果多个,再根据名称注入
BookDao bookDao;现根据BookDao这个类型注入,然后根据bookDao这个名称;如果没有就会报错,可以使用
required = false来处理,当有多个类型的Dao我们可以使用@Qualifier来指定具体的某个Dao对象.当有多个Dao我们又没有指定,我们想优先加载某个Dao对象,那么可以在创建这个Dao的地方加上@Primary注解,表示优先加载这个Dao,这里仅仅使用Dao来举例,其他要注入的对象使用原则一致
@Autowired使用范围
1).使用在属性上,我们经常用的
2):使用在构造方法上
这样获取回来的dog对象是spring容器中的对象
3)使用在参数列表上面
7.3:@Resource---java规范注解
1. 如果同时指定了name和type,则从Spring上下文中找到唯一匹配的bean进行装配,找不到则抛出异常
2. 如果指定了name,则从上下文中查找名称(id)匹配的bean进行装配,找不到则抛出异常
3. 如果指定了type,则从上下文中找到类型匹配的唯一bean进行装配,找不到或者找到多个,都会抛出异常
4. 如果既没有指定name,又没有指定type,则自动按照byName方式进行装配;如果没有匹配,则回退为一个原始类型进行匹配,如果匹配则自动装配;
不支持@primary,没有@autowired(required=false)的功能
7.4:使用@Inject---java规范注解
需要导入javax.inject包,和Autowird功能一样,能支持@Primary,只是没有required=false的功能.
8:aware注入spring底层组件及其原理
自定义的组件想使用spring底层的组件,比如说applicationContext,beanFactory都有对应的aware接口,我们自定义的组件实现我们想使用的spring底层组件对应的aware接口就行了.
比如我想使用一下ApplicationContext,就需要实现ApplicationContextAware接口,然后实现里面的setApplicationContext方法,设置ApplicationContext就行了.
原理:通过断点我们可以看到进入到了ApplicationContextAwareProcessor的postProcessBeforeInitialization方法中,该类实现了
BeanPostProcessor,这个我们都知道是在初始化前后做一些操作的.然后进去invokeAwareInterfaces方法中,可以看到调用了setApplicationContext方法,invokeAwareInterfaces中的bean参数就是我们自定义组件对象,也就是实现ApplicationContextAware接口的对象,我这里是pig对象,所以就是调用pig对象中的setApplicationContext方法.
9.从配置文件读取配置文件
使用@propertySource("classpath:***.properties")指定数据源
9.1:在属性上面我们使用@Value("${配置文件的字段}")
9.2:在参数列表上面使用@Value("${配置文件的字段}")
9.3:配置文件类实现EmbeddedValueResoleverAware接口,实现setEmbeddedValueResolver,注入resolver;调用resolver.resolverStringValue("${配置文件中的字段}")方法来解析数据.获取配置文件
10:使用@Profile根据环境注册对应的组件
/**
* Profile:
* Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;
*
* 开发环境使用A数据源、测试环境使用B数据源、生产环境使用C数据源;
*
*
* @Profile:指定组件在哪个环境的情况下才能被注册到容器中,如果不指定,任何环境下都能注册这个组件:例如Yellow组件
*
* 1)、加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
* 2)、如果@Profile写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
* 3)、没有标注环境标识的bean在,任何环境下都是加载的;
*/
@PropertySource("classpath:/dbconfig.properties")
@Configuration
public class MainConfigOfProfile /**从配置文件获取数据方式3*/implements EmbeddedValueResolverAware{
//从配置文件获取数据方式1
@Value("${db.user}")
private String user;
private StringValueResolver valueResolver;
private String driverClass;
@Bean
public Yellow yellow(){
return new Yellow();
}
@Profile("test")//测试环境才设置这个数据源
@Bean("testDataSource")
public DataSource dataSourceTest(/**从配置文件获取数据方式2*/@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;
}
@Profile("dev")//开发环境设置这个数据源
@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;
}
@Profile("prod")//生产环境设置这个数据源
@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;
}
//从配置文件获取数据方式3,解析配置文件中的值
@Override
public void setEmbeddedValueResolver(StringValueResolver resolver) {
// TODO Auto-generated method stub
this.valueResolver = resolver;
driverClass = valueResolver.resolveStringValue("${db.driverClass}");
}
}
测试激活环境方式:
1、使用命令行动态参数: 在虚拟机参数位置加载 -Dspring.profiles.active=test,在下面图片idea中配置jvm运行参数
2、代码的方式激活某种环境;例如下面激活的是dev的环境
//1、使用命令行动态参数: 在虚拟机参数位置加载 -Dspring.profiles.active=test
//2、代码的方式激活某种环境;
@Test
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();
}