码迷,mamicode.com
首页 > 编程语言 > 详细

Spring中构造器、init-method、@PostConstruct、afterPropertiesSet孰先孰后,自动注入发生时间以及单例多例的区别

时间:2018-08-04 01:00:56      阅读:811      评论:0      收藏:0      [点我收藏+]

标签:单例模式   nbsp   ack   默认   tac   print   类的构造函数   需求   .com   

  

  首先明白,spring的IOC功能需要是利用反射原理,反射获取类的无参构造方法创建对象,如果一个类没有无参的构造方法spring是不会创建对象的。在这里需要提醒一下,如果我们在class中没有显示的声明构造方法,默认会生成一个无参构造方法,但是当我们显示的声明一个有参构造方法的时候,JVM不会帮我们生成无参构造方法,所以我们声明一个带参数的构造方法也需要声明一个无参构造方法。(题外话:如果父类声明一个有参构造方法,子类需要在构造方法第一行显示的调用父类构造方法,因为子类的对象也是父类的对象,所以在创建子类对象的同时也会创建父类的对象,如果父类有默认的无参构造函数,JVM会调用无参构造函数,但是有了有参的就需要我们在子类的构造函数中调用父类的有参构造函数)

 

 1.Person类只有一个有参构造方法,报错如下:

No default constructor found; nested exception is java.lang.NoSuchMethodException: zd.dms.job.ebuy.Person.<init>()

 

 

2.大体知道有三种生命周期回调方法去参与到spring的生命周期,查阅了一下如下:(创建和销毁的执行顺序也是下面顺序)

  • 在指定方法上加上@PostConstruct 或@PreDestroy注解来制定该方法是在初始化之后还是销毁之前调用。
  • 通过实现 InitializingBean/DisposableBean 接口来定制初始化之后/销毁之前的操作方法;     
  • 通过 <bean> 元素的 init-method/destroy-method属性指定初始化之后 /销毁之前调用的操作方法;  

 

 

3.测试spring的顺序与注入的顺序与单例多例的问题

1.Person.java

package zd.dms.job.ebuy;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;

import zd.dms.dao.ebuy.GroupDao;

public class Person implements InitializingBean,DisposableBean{
    private String name;
    
    @Autowired
    private GroupDao groupDao;

    public Person() {
        System.out.println("---------------实例化一个Person对象----------");
        System.out.println("---------------groupDao is -----------"+groupDao);
    }

    public void init() {
        System.out.println("------------这是xml的init方法----------....");
        System.out.println("---------------groupDao is -----------"+groupDao);
    }

    public void destory() {
        System.out.println("---------------这是xml的destroy方法....");
        System.out.println("---------------groupDao is -----------"+groupDao);
    }
    
    @PostConstruct
    public void init2() {
        System.out.println("------------这是@PostConstruct的init方法----------....");
        System.out.println("---------------groupDao is -----------"+groupDao);
    }
    
    @PreDestroy
    public void destory2() {
        System.out.println("---------------这是@PreDestroy的destroy方法....");
        System.out.println("---------------groupDao is -----------"+groupDao);
    }

    @Override
    public void destroy() throws Exception {
        System.out.println("-----------这是DisposableBean的destroy方法....");
        System.out.println("---------------groupDao is -----------"+groupDao);
    }

    @Override
    public void afterPropertiesSet() throws Exception {
        System.out.println("-------这是InitializingBean的afterPropertiesSet方法....");
        System.out.println("---------------groupDao is -----------"+groupDao);
    }
}

 

 -----------------------单例模式的xml配置以及结果---------------------------------------:

配置:

    <bean id="person" class="zd.dms.job.ebuy.Person" autowire="byType" destroy-method="destory" init-method="init"></bean> 

 

测试:将Person类注入到Action我们访问Action

@Namespace("/qlqTest")
@SuppressWarnings("all")
public class TestAction extends DMSActionSupport{

    /**
     * 
     */
    private static final long serialVersionUID = -8934360924125349297L;
    
    @Autowired
    private GroupAndUserService groupAndUserService;
    @Autowired
    private Person person;

 

 

当我们第一次调用该实例方法的时候会创建对象,打印结果如下:

- ---------------实例化一个Person对象----------
---------------groupDao is -----------null
------------这是@PostConstruct的init方法----------....
---------------groupDao is -----------zd.dms.dao.ebuy.GroupDaoImpl@435598e3
-------这是InitializingBean的afterPropertiesSet方法....
---------------groupDao is -----------zd.dms.dao.ebuy.GroupDaoImpl@435598e3
------------这是xml的init方法----------....
---------------groupDao is -----------zd.dms.dao.ebuy.GroupDaoImpl@435598e3

 

 

 

证明对象创建的顺序:

    构造器-->自动注入-->@PostConstrut-->InitializingBean-->xml中配置init方法    

 

再次调用不会打印,证明默认是单例的  singleton,也就是无论我们访问多少次Action,Spring容器中只有一个这个对象。

 

销毁的时候的结果:

---------------这是@PreDestroy的destroy方法....
---------------groupDao is -----------zd.dms.dao.ebuy.GroupDaoImpl@435598e3
-----------这是DisposableBean的destroy方法....
---------------groupDao is -----------zd.dms.dao.ebuy.GroupDaoImpl@435598e3
---------------这是xml的destroy方法....
---------------groupDao is -----------zd.dms.dao.ebuy.GroupDaoImpl@435598e3

 

所以销毁顺序为:

  @PreDestroy--DisposableBean-->xml中destroy-method方法

 

 

 

 -----------------------多模式的xml配置以及结果---------------------------------------:

配置:

<bean id="person" class="zd.dms.job.ebuy.Person" autowire="byType" destroy-method="destory" init-method="init" scope="prototype"></bean>

 

 

我们多次访问Action,所以Action会多次调用Person对象,发现会多次创建Person对象,也就是请求一次会创建一个对象,也就是多例:

技术分享图片

 

 

 

 

 至于到底是该使用单例还是多例,这就需要我们平时的业务需求了,springMvc就是单例的,struts2默认就是多例的。我们也可以使用注解配置单例和多例,如下:

技术分享图片

 

 技术分享图片

 

 

---------------------为了理解上面的单例多例的例子,继续测试---------------------

配置如下:

技术分享图片

 

技术分享图片

技术分享图片

 

 

技术分享图片

 

 

Action是struts默认多例:(注入Person类对象)

Person类模拟是service层,默认是单例(注入GroupDaoImpl对象)

GroupDaoImpl是多例

 也就是我们上面的配置从Action到service到dao的作用域是多-单-多,我们多次访问Action,结果如下:

技术分享图片

解释:

  我们每次访问action是多例所以每次会创建对象,而Person默认是单例,所以spring只会维护一个对象,即使GroupDaoImpl是多例模式,但是其已经注入到Person类中,而person不会创建新的对象,所以GroupDaoImpl也只会生成一个对象。只有在生成Person类的时候才会重新生成GroupDaoImpl且重新维护关系。所以上面在spring中出现对各TestAction,一个Person和一个GroupDaoImpl。

 

Spring中构造器、init-method、@PostConstruct、afterPropertiesSet孰先孰后,自动注入发生时间以及单例多例的区别

标签:单例模式   nbsp   ack   默认   tac   print   类的构造函数   需求   .com   

原文地址:https://www.cnblogs.com/qlqwjy/p/9417034.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!