一.生命周期

  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实现整数翻转

    ** 整数翻转** 以下程序把一个整数翻转(8765变为:5678),请补充缺少的代码. int n = 8765; int m = 0; while(n>0) { m = __________ ...

  2. CVE¬-2020-¬0796 漏洞复现(本地提权)

    CVE­-2020-­0796 漏洞复现(本地提权) 0X00漏洞简介 Microsoft Windows和Microsoft Windows Server都是美国微软(Microsoft)公司的产品 ...

  3. 使用root配置的hadoop并启动会出现报错

    1.使用root配置的hadoop并启动会出现报错 错误:         Starting namenodes on [master]         ERROR: Attempting to op ...

  4. 温故知新-java虚拟机

    文章目录 java虚拟机是什么? jvm的体系结构 第一个类加载子系统 类的生命周期 加载器分类 类加载机制 第二个运行时数据区(内存结构) GC算法和收集器 如何判断对象可以被回收? 如何判断一个常 ...

  5. AndroidCamera开发学习笔记01

    概述 Android框架支持设备的相机拍照和录像功能 可以直接调用系统的Camera应用来拍照或录像 也可以利用Adroid系统提供的API开发Camera应用来实现拍照和录像的功能 注意事项 需要硬 ...

  6. 源码分析(1)-HashMap(JDK1.8)

    UML类图 java.util.Map<K, V>接口,有4个实现类:HashMap.Hashtable.LinkedHashMap和TreeMap. 1.说明 (1)HashMap除允许 ...

  7. 「MoreThanJava」Java发展史及起航新世界

    「MoreThanJava」 宣扬的是 「学习,不止 CODE」,本系列 Java 基础教程是自己在结合各方面的知识之后,对 Java 基础的一个总回顾,旨在 「帮助新朋友快速高质量的学习」. 当然 ...

  8. PMBOK 基础知识(1)

    启动.结束过程 项目管理计划 第一章  引论 第2章项目运行环境 第3章 项目经理的角色 第4章 项目整合管理 第5章 项目范围管理 第6章 项目进度管理 第7章 项目成本管理 第8章 项目质量管理  ...

  9. PAI-AutoLearning 图像分类使用教程

    概述 PAI AutoLearning(简称PAI AL)自动学习支持在线标注.自动模型训练.超参优化以及模型评估.在平台上只需准备少量标注数据,设置训练时长即可得到深度优化的模型.同时自动学习PAI ...

  10. python第三方库大全

    环境管理 管理 Python 版本和环境的工具 p:非常简单的交互式 python 版本管理工具.官网 pyenv:简单的 Python 版本管理工具.官网 Vex:可以在虚拟环境中执行命令.官网 v ...