一.生命周期

  1. @Bean自定义初始化和销毁方法

    //====xml方式: init-method和destroy-method====
    <bean id="person" class="com.hrh.bean.Person" scope="singleton" init-method="" destroy-method="">
    <property name="name" value="张三"></property>
    <property name="age" value="20"></property>
    </bean>
    //====@Bean方式====
    /**
    *单实例:只调用initMethod一次,容器关闭时会调用destroyMethod
    *多实例: 每次调用Bean都调用initMethod,容器关闭不会调用destroyMethod,需要手动调用
    **/
    @Bean(initMethod = "",destroyMethod = "")
    public Person person() {
    System.out.println("注入容器。。。。。");
    return new Person("张三", 20);
    }
    //====实现接口方式====
    /**
    * InitializingBean:定义初始化逻辑,实现afterPropertiesSet()
    * DisposableBean:定义销毁逻辑,实现destroy()
    */
    @Component
    public class Person implements InitializingBean, DisposableBean {
    public Person(){
    System.out.println("Person 。。。 constructor");
    } @Override
    public void afterPropertiesSet() throws Exception {
    System.out.println("Person 。。。afterPropertiesSet");
    } @Override
    public void destroy() throws DestroyFailedException {
    System.out.println("Person 。。。destroy");
    }
    }
    @Configurable
    @ComponentScan(value = "com.hrh")
    public class BeanConfig {} AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
    context.close();
  2. @PostConstruct和@PreDestroy

    /**
    * JSR250:
    * @PostConstruct: 在bean创建完成并且属性赋值完成后,来执行初始化方法
    * @PreDestroy :在容器销毁bean之前通知进行清理工作
    */
    @Component
    public class Color {
    public Color() {
    System.out.println("Color 。。。 constructor");
    } @PostConstruct//对象创建并赋值之后调用
    public void init() throws Exception {
    System.out.println("Color 。。。init");
    } @PreDestroy//容器移除对象之前
    public void destroy() {
    System.out.println("Color 。。。destroy");
    }
    }
  3. BeanPostProcessor:bean后置处理器,对bean初始化之前和之后的处理,上文的@PostConstruct和@PreDestroy就是使用了该类实现的

        @Component
    public class MyBeanPostProcessor implements BeanPostProcessor {
    /**
    *
    * @param bean 容器创建的实例
    * @param beanName 容器创建实例的名字
    * @return 创建的实例或进行包装后的实例
    * @throws BeansException
    */
    @Override
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("postProcessBeforeInitialization====>【"+bean+"】:"+beanName);
    return bean;
    } @Override
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
    System.out.println("postProcessAfterInitialization====>【"+bean+"】:"+beanName);
    return bean;
    }
    }
    public static void main(String[] args) {
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
    }
    • 原理:从doCreateBean可以看到,在对bean进行属性赋值后,调用initializeBean初始化bean,在initializeBean中会在调用初始化方法前后会遍历所有的BeanPostProcessor实现的方法

          AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
      public AnnotationConfigApplicationContext(Class<?>... annotatedClasses) {
      ....
      refresh();//刷新容器
      }
      public void refresh() throws BeansException, IllegalStateException {
      ...
      //初始化剩下所有的(非懒加载的)单实例对象
      finishBeanFactoryInitialization(beanFactory);
      }
      protected void finishBeanFactoryInitialization(ConfigurableListableBeanFactory beanFactory) {
      ...
      //初始化剩下所有的(非懒加载的)单实例对象
      beanFactory.preInstantiateSingletons();
      }
      public void preInstantiateSingletons() throws BeansException {
      ...
      getBean(beanName);
      ...
      }
      @Override
      public Object getBean(String name) throws BeansException {
      return doGetBean(name, null, null, false);
      }
      protected <T> T doGetBean(
      final String name, final Class<T> requiredType, final Object[] args, boolean typeCheckOnly)
      throws BeansException {
      ...
      //getSingleton获取实例
      sharedInstance = getSingleton(beanName, new ObjectFactory<Object>() {
      @Override
      public Object getObject() throws BeansException {
      try {
      return createBean(beanName, mbd, args);//创建实例
      }
      ...
      }
      });
      ...
      return (T) bean;
      } protected Object createBean(String beanName, RootBeanDefinition mbd, Object[] args) throws BeanCreationException {
      ...
      Object beanInstance = doCreateBean(beanName, mbdToUse, args);//创建实例
      ...
      return beanInstance;
      }
      protected Object doCreateBean(final String beanName, final RootBeanDefinition mbd, final Object[] args) {
      ...
      Object exposedObject = bean;
      try {
      populateBean(beanName, mbd, instanceWrapper);//对属性赋值
      if (exposedObject != null) {
      exposedObject = initializeBean(beanName, exposedObject, mbd);//初始化对象,相当后置处理器的调用
      }
      }
      ...
      return exposedObject;
      }
      //从下面可以看到,在执行初始化方法之前,执行applyBeanPostProcessorsBeforeInitialization,执行完初始化方法之后,执行applyBeanPostProcessorsAfterInitialization
      protected Object initializeBean(final String beanName, final Object bean, RootBeanDefinition mbd) {
      ...
      wrappedBean = applyBeanPostProcessorsBeforeInitialization(wrappedBean, beanName);
      ...
      invokeInitMethods(beanName, wrappedBean, mbd);//执行初始化方法
      ...
      wrappedBean = applyBeanPostProcessorsAfterInitialization(wrappedBean, beanName);
      return wrappedBean;
      }
      @Override
      public Object applyBeanPostProcessorsBeforeInitialization(Object existingBean, String beanName)
      throws BeansException {
      Object result = existingBean;
      //遍历执行实现了BeanPostProcessor接口的类,比如MyBeanPostProcessor,然后执行实现类的重写方法
      for (BeanPostProcessor beanProcessor : getBeanPostProcessors()) {
      result = beanProcessor.postProcessBeforeInitialization(result, beanName);
      if (result == null) {
      return result;
      }
      }
      return result;
      }
    • InitDestroyAnnotationBeanPostProcessor:处理@PostConstruct和@PreDestroy

          /**
      * 处理javax.annotation.PostConstruct注解
      */
      public void setInitAnnotationType(Class<? extends Annotation> initAnnotationType) {
      this.initAnnotationType = initAnnotationType;
      }
      /**
      * 处理javax.annotation.PreDestroy注解
      */
      public void setDestroyAnnotationType(Class<? extends Annotation> destroyAnnotationType) {
      this.destroyAnnotationType = destroyAnnotationType;
      }
      public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      //找到了使用@PostConstruct和@PreDestroy的类的生命周期注解
      LifecycleMetadata metadata = findLifecycleMetadata(bean.getClass());
      try {
      //对每个注解上的方法进行反射执行
      metadata.invokeInitMethods(bean, beanName);
      }
      catch (InvocationTargetException ex) {
      throw new BeanCreationException(beanName, "Invocation of init method failed", ex.getTargetException());
      }
      catch (Throwable ex) {
      throw new BeanCreationException(beanName, "Failed to invoke init method", ex);
      }
      return bean;
      }
      public void invokeInitMethods(Object target, String beanName) throws Throwable {
      Collection<LifecycleElement> checkedInitMethods = this.checkedInitMethods;
      Collection<LifecycleElement> initMethodsToIterate =
      (checkedInitMethods != null ? checkedInitMethods : this.initMethods);
      if (!initMethodsToIterate.isEmpty()) {
      for (LifecycleElement element : initMethodsToIterate) {
      if (logger.isTraceEnabled()) {
      logger.trace("Invoking init method on bean '" + beanName + "': " + element.getMethod());
      }
      //element包含注解和注解上的方法
      element.invoke(target);//执行每个注解上的方法
      }
      }

二.属性赋值

  1. @Value

    public class Person {
    /**
    * @Value :基本数值,SpEL表达式 #{}, ${}获取配置文件的值
    */
    @Value("张三")
    private String name;
    @Value("#{20-1}")
    private Integer age;
    }
  2. @PropertySource:读取外部配置文件中k/v的数据

    public class Person{
    /**
    * @Value :基本数值,SpEL表达式 #{}, ${}获取配置文件的值
    */
    @Value("张三")
    private String name;
    @Value("#{20-1}")
    private Integer age;
    @Value("${sex}")
    private String sex;
    }
    @PropertySource(value = "classpath:/global.properties")
    @Configurable
    public class BeanConfig {} global.properties
    sex=男

三.自动装配

  1. @Autowired&@Qualifier&@Primary:Spring定义

    @Service
    public class UserService {
    /**
    * @Autowired :自动注入
    * 1)默认优先按照类型去容器中对应的组件:context.getBean(UserDao.class);
    * 2)如果有多少相同类型的组件,需要将属性的名称作为id去容器查找:(UserDao) context.getBean("userDao1")
    * 3)@Qualifier("userDao1"):指定需要装配的组件id,而不是使用默认属性;优先级比@Primary高
    * 4)如果UserDao没有注入容器(@Repository和 @Bean):启用@Autowired会报空指针异常,需要required = false,表示从容器中找到就自动装配,找不到就设为null
    * 5)@Primary表示Spring自动装配时,默认使用首选的bean
    */
    @Qualifier("userDao")
    @Autowired
    private UserDao userDao; public void printf() {
    System.out.println(userDao);
    }
    }
    @Repository
    public class UserDao {
    private String id ="1"; public String getId() {
    return id;
    } public void setId(String id) {
    this.id = id;
    } @Override
    public String toString() {
    return "UserDao{" +
    "id='" + id + '\'' +
    '}';
    }
    }
    @Configurable
    @ComponentScan(value = "com.hrh")
    public class BeanConfig {
    @Primary
    @Bean("userDao1")
    public UserDao userDao() {
    UserDao userDao = new UserDao();
    userDao.setId("2");
    return userDao;
    }
    }
    AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(BeanConfig.class);
    UserService person = context.getBean(UserService.class);
    person.printf();
    //UserDao userDao = context.getBean(UserDao.class);
    UserDao userDao =(UserDao) context.getBean("userDao1");
    System.out.println(userDao);
  2. @Resource&@Inject:Java规范

    1. @Resource:只按照属性名称进行装配,可以使用@Resource(name = "")装配指定id;不支持@Primary的使用,即使用该注解是无效的;

    2. @Inject:支持自动装配,和@Autowired功能一样,支持@Primary的使用;没有required = false属性;

  3. Aware注入Spring底层组件&原理

    • 自定义组件使用Spring容器底层的一些组件(ApplicationContext、BeanFactory...),实现xxxAware

      public class Color  implements ApplicationContextAware {
      private ApplicationContext applicationContext;
      //获取容器并赋值给当前类
      @Override
      public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
      this.applicationContext = applicationContext;
      }
      }
    • xxxAware使用对应的xxxAwareProcessor进行处理:利用后置处理器在类初始化时注入组件

          //bean:获得实现了ApplicationContextAware接口的类,即Color
      public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
      //类型判断
      if (!(bean instanceof EnvironmentAware || bean instanceof EmbeddedValueResolverAware ||
      bean instanceof ResourceLoaderAware || bean instanceof ApplicationEventPublisherAware ||
      bean instanceof MessageSourceAware || bean instanceof ApplicationContextAware)){
      return bean;
      } AccessControlContext acc = null; if (System.getSecurityManager() != null) {
      acc = this.applicationContext.getBeanFactory().getAccessControlContext();
      } if (acc != null) {
      //权限检查
      AccessController.doPrivileged((PrivilegedAction<Object>) () -> {
      invokeAwareInterfaces(bean);
      return null;
      }, acc);
      }
      else {
      invokeAwareInterfaces(bean);//转换并注入组件
      } return bean;
      } private void invokeAwareInterfaces(Object bean) {
      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) {
      //给当前类注入ApplicationContext
      ((ApplicationContextAware) bean).setApplicationContext(this.applicationContext);
      }
      }
  4. @Profile:指定组件在哪个环境的情况下才能被注册到容器中

    • 加了环境标识的bean,只有在指定环境才能被注册到容器中,默认是default环境
    • 写在配置类上,只有是指定环境整个配置类里面的所有配置才能生效
    • 没有环境标识的bean在任何环境下都会被注册到容器中
      @PropertySource("classpaht:/db.properties")
      @Configuration
      public class BeanProfileConfig {
      @Value("${db.user}")
      private String user;
      @Value("${db.driverClass}")
      private String driverClass; @Profile("test")
      @Bean
      public DataSource TestDateSource(@Value("${db.password}") String pwd) throws PropertyVetoException {
      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
      public DataSource DevDateSource(@Value("${db.password}") String pwd) throws PropertyVetoException {
      ComboPooledDataSource dataSource = new ComboPooledDataSource();
      dataSource.setUser(user);
      dataSource.setPassword(pwd);
      dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/dev");
      dataSource.setDriverClass(driverClass);
      return dataSource;
      } @Profile("pro")
      @Bean
      public DataSource ProDateSource(@Value("${db.password}") String pwd) throws PropertyVetoException {
      ComboPooledDataSource dataSource = new ComboPooledDataSource();
      dataSource.setUser(user);
      dataSource.setPassword(pwd);
      dataSource.setJdbcUrl("jdbc:mysql://localhost:3306/pro");
      dataSource.setDriverClass(driverClass);
      return dataSource;
      }
      }
      /**
      * 1.使用命令行动态参数:在虚拟机参数位置加载 -Dspring.profiles.active=test
      * 2.代码方式:创建无参容器,设置激活环境
      */
      //创建容器
      AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();
      //设置需要激活的环境
      context.getEnvironment().setActiveProfiles("test");
      //注册主配置类
      context.register(BeanProfileConfig.class);
      //启动刷新容器
      context.refresh(); 

Spring笔记(2) - 生命周期/属性赋值/自动装配及部分源码解析的更多相关文章

  1. 你还不知道Vue的生命周期吗?带你从Vue源码了解Vue2.x的生命周期(初始化阶段)

    作者:小土豆biubiubiu 博客园:https://www.cnblogs.com/HouJiao/ 掘金:https://juejin.im/user/58c61b4361ff4b005d9e8 ...

  2. Java基础知识强化之集合框架笔记11:Collection集合之迭代器的原理及源码解析

    1. 迭代器为什么不定义成一个类,而是定义为一个接口 ?  答:假设迭代器定义的是一个类,这样我们就可以创建该类的对象,调用该类的方法来实现集合的遍历.但是呢? 我们想想,Java中提供了很多的集合类 ...

  3. Spring系列(三):Spring IoC源码解析

    一.Spring容器类继承图 二.容器前期准备 IoC源码解析入口: /** * @desc: ioc原理解析 启动 * @author: toby * @date: 2019/7/22 22:20 ...

  4. springboot源码解析-管中窥豹系列之自动装配(九)

    一.前言 Springboot源码解析是一件大工程,逐行逐句的去研究代码,会很枯燥,也不容易坚持下去. 我们不追求大而全,而是试着每次去研究一个小知识点,最终聚沙成塔,这就是我们的springboot ...

  5. 【spring 注解驱动开发】spring对象的生命周期

    尚学堂spring 注解驱动开发学习笔记之 - 生命周期 生命周期 1.生命周期-@Bean指定初始化和销毁方法 2.生命周期-InitializingBean和DisposableBean 3.生命 ...

  6. Spring Bean的生命周期,《Spring 实战》书中的官方说法

    连着两天的面试 ,都问到了 Spring 的Bean的生命周期,其中还包括 昨晚一波阿里的电话面试.这里找到了Spring 实战中的官方说法.希望各位要面试的小伙伴记住,以后有可能,或者是有时间 去看 ...

  7. Spring学习手札(四)谈谈Spring Bean的生命周期及作用域

    在Spring中,那些组成应用程序的主体以及由Spring IoC容器所管理的对象,被称之为Bean.Bean与应用程序中其他对象(比如自己创建类)的区别就是,Bean是由IoC容器创建于销毁的.在S ...

  8. Spring动态代理及Spring Bean的生命周期

    数组添加值 public class DiTest { /** * 数组 */ private String [] arrays; /** * List:集合 */ private List<I ...

  9. Spring(三)--Spring bean的生命周期

    Spring bean的生命周期 ApplicationContext Bean生命周期流程 1.需要的实体类 ackage com.xdf.bean; import org.springframew ...

随机推荐

  1. Java实现 蓝桥杯VIP 算法提高 铺地毯

    算法提高 铺地毯 时间限制:1.0s 内存限制:256.0MB 问题描述 为了准备一个学生节,组织者在会场的一片矩形区域(可看做是平面直角坐标 系的第一象限)铺上一些矩形地毯.一共有n 张地毯,编号从 ...

  2. Java实现 LeetCode 106 从中序与后序遍历序列构造二叉树

    106. 从中序与后序遍历序列构造二叉树 根据一棵树的中序遍历与后序遍历构造二叉树. 注意: 你可以假设树中没有重复的元素. 例如,给出 中序遍历 inorder = [9,3,15,20,7] 后序 ...

  3. Java实现蓝桥杯调和级数

    1/1 + 1/2 + 1/3 + 1/4 + - 在数学上称为调和级数. 它是发散的,也就是说,只要加上足够多的项,就可以得到任意大的数字. 但是,它发散的很慢: 前1项和达到 1.0 前4项和才超 ...

  4. Java实现找零问题

    1 问题描述 现需找零金额为n,则最少需要用多少面值为d1 < d2 < d3 < - < dm的硬币?(PS:假设这m种面值d1 < d2 < d3 < - ...

  5. java实现蓝桥杯密码脱落

    一 问题描述 X星球的考古学家发现了一批古代留下来的密码. 这些密码是由A.B.C.D 四种植物的种子串成的序列. 仔细分析发现,这些密码串当初应该是前后对称的(也就是我们说的镜像串). 由于年代久远 ...

  6. Java实现第十届蓝桥杯数列求值

    试题 C: 数列求值 本题总分:10 分 [问题描述] 给定数列 1, 1, 1, 3, 5, 9, 17, -,从第 4 项开始,每项都是前 3 项的和.求 第 20190324 项的最后 4 位数 ...

  7. CentOS7搭建Pacemaker高可用集群(1)

    Pacemaker是Red Hat High Availability Add-on的一部分.在RHEL上进行试用的最简单方法是从Scientific Linux 或CentOS存储库中进行安装 环境 ...

  8. 使用Json框架解析遇到Java关键字时的解决方案

    当Json数据中的key为Java关键字时,在定义实体类的时候不能对该字段进行声明,所以需要对字段进行特殊处理 使用Gson解析 在与Java关键字冲突的字段加上@SerializedName注解 @ ...

  9. 从mysql数据库中查询最新的一条数据的方法

    第一种方法 SELECT * from a where id = (SELECT max(id) FROM a); 第二种方法: select * FROM 表名 ORDER BY id DESC L ...

  10. 0.1---selenium+java自动化测试进阶02----项目实战之登录代码重构

    一.测试登录功能实现 以慕课网的登录为例,分析登录的功能需求,编写测试用例,找到要定位的元素以及需要的操作,编写登录功能的测试代码.代码实现如下: public static void main(St ...