Spring源码注解解析day02

bean的生命周期:

构造:

单实例:在容器启动的时候进行构造;

多实例:在第一调用bean的时候进行构造;

初始化:

对象创建好之后,首先会进行赋值,然后开始调用初始方法。

销毁:

单实例:在容器销毁的时候进行销毁;

多实例:容器不会管,根据自己的情况进行销毁;

创建初始方法以及销毁方法的几种方式:

1)3通过@Bean指定,选择属性init-method或者destory-method来指定,destory-method只对单例bean有效,方法必须是无参

    @Bean(value = "person1", initMethod = "init", destroyMethod = "destory")
    public Person person() {
        return new Person();
    }

2)1通过让bean实现InitializingBean接口,重写方法afterPropertiesSet方法,实现初始化完成,该方法是该bean实例化完成,并且赋值以后调用;同时也可以实现DisposableBean接口,重写destory方法,实现销毁后调用改方法;但是只对单例bean有效。

public class Person implements InitializingBean, DisposableBean {

    public void destroy() throws Exception {
        System.out.println("初始化方法。。。");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("销毁方法。。。");
    }
}

3)2通过java注解JSR250的@PostConstruct来定义在方法上,就代表是初始化方法,@PreDestroy代表销毁方法;

需要导入jsr250-api的依赖.

    @PostConstruct
    public void init2() {
        System.out.println("初始化方法。。。2");
    }

    @PreDestroy
    public void destory2() {
        System.out.println("销毁方法。。。2");
    }

 经测试:三种都是在bean自定义初始化方法,并且赋值后才开始执行,但是也有一个顺序;初始化方法、销毁方法的顺序是  第二种==》第三种 ==》第一种

bean的初始化前后处理器BeanPostProcessor接口

实现该接口后,要重写两个方法:

1)postProcessBeforeInitialization  该方法是在创建对象,给属性赋值后马上调用,在初始化方法之前调用;

2)postProcessAfterInitialization  该方法就是在初始化方法调用之后进行;

利用这个原理,spring底层很多都是通过这个方法来实现很多东西;

比如:

1)@Autowired自动注解就是通过该原理实现;

2)最经典的就是上面说的实现初始化方法;为什么单单在一个方法上面写一个注解就会让容器在初始化的时候执行呢?

答案就是:通过postProcessBeforeInitialization的方法在初始化之前查看初始化的bean的注解信息,当看到有要执行初始化的注解的时候,就会通过反射的方法来执行。所以说spring也大量利用了这个特性进行开发。

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {


    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanPostProcessor   ---   postProcessBeforeInitialization   ---" + beanName);
        return bean;
    }

    @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("MyBeanPostProcessor   ---   postProcessAfterInitialization  ---" + beanName);
        return bean;
    }
}

上一小节说的三种bean的自定义初始化方法都是在postProcessBeforeInitialization之后,postProcessAfterInitialization之前执行的

bean的属性赋值:

可以通过@Value注解、获取环境变量等方式进行赋值,同事里面可以写SPEL表达式,以及${ }来获取配置文件的信息传值给属性;

@Value("张三")
private String name;

@Value("#{20-2}")
private Integer age;

@Value("${person.nickName}")
private String nickName;

//容器获取到环境变量,然后通过环境变量来获取,因为配置文件在加载中都会到环境变量里面
ConfigurableEnvironment environment = applicationContext.getEnvironment();
String property = environment.getProperty("person.nickName");

@Profile注解的使用:

@Profile("test")
	@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;
	}
	
	
	@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;
	}

配置三个数据源的对象,代表每个数据源在不同环境下才能使用,在创建容器的时候根据不同的环境来获取不同的数据源:

AnnotationConfigApplicationContext applicationContext = 
				                      new AnnotationConfigApplicationContext();
		//1、创建一个applicationContext
		//2、设置需要激活的环境
		applicationContext.getEnvironment().setActiveProfiles("dev");
		//3、注册主配置类
		applicationContext.register(MainConfigOfProfile.class);
		//4、启动刷新容器
		applicationContext.refresh();

这样子就只能获取“dev”模式下的数据源:补充一点:如果一个bean没有配置@Profile注解会不会被创建呢?

答案:肯定会啦,不然的话每个都要写,麻烦死了,没有@Profile注解的bean是全部都会被创建的。

下面是详细讲解最后一个IOC的注解了。

@Autowired:自动注入:

该功能的强大,大家都知道。下面详细讲解使用它的几个规则:

1)默认优先按照类型去容器中找对应的组件:applicationContext.getBean(BookDao.class);找到就赋值;

2)如果找到多个可以匹配的类型bean,它会自动在通过将实例名字作为id去找;

3)@Qualifier("bookDao")使用@Qualifier指定需要装配的组件的id,而不是使用属性名,权利最大,只要指定了,就是它了;

4)在自动装配中,如果没有找到合适的bean就会报错,可以通过@Autowired(required=false)的方法来不让它报错;

5)@Primary:让Spring进行自动装配的时候,默认使用首选的bean;也可以继续使用@Qualifier指定需要装配的bean的名字

备注:@Qualifier  >   @Primary

上面是Spring带的@Autowired:自动注入,下面说明几个不是spring的,照样可以进行自动注入。

@Resource(JSR250)和@Inject(JSR330)[java规范的注解]:

1)@Resource:可以和@Autowired一样实现自动装配功能;默认是按照组件名称进行装配的;没有能支持@Primary功能没有支持@Autowired(reqiured=false);
2)@Inject:需要导入javax.inject的包,和Autowired的功能一样。没有required=false的功能;

所以对比这几个自动注入的方法,还是@Autowired比较好用;

在说明一下,@Autowired不仅仅可以使用在属性上,方法、构造器、参数都可以使用哦!

最后一点小知识   

自定义组件想要使用Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx);
自定义组件实现xxxAware;在创建对象的时候,会调用接口规定的方法注入相关组件;Aware;
把Spring底层一些组件注入到自定义的Bean中;
 xxxAware:功能使用xxxProcessor;
ApplicationContextAware==》ApplicationContextAwareProcessor;

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值