>  기사  >  웹 프론트엔드  >  Spring 수명주기 및 컨테이너 확장 사용법에 대한 자세한 설명

Spring 수명주기 및 컨테이너 확장 사용법에 대한 자세한 설명

php中世界最好的语言
php中世界最好的语言원래의
2018-04-13 14:45:181688검색

이번에는 Spring라이프사이클과 컨테이너 확장 사용에 대한 자세한 설명을 가져왔습니다. Spring 라이프사이클 및 컨테이너 확장 사용 시 주의사항은 무엇인가요?

다음은 주요 소개입니다.

클래스 수준 수명 주기 초기화 콜백 메소드 init-method 구성, InitializingBean 인터페이스 및 PostConstruct 주석

컨테이너 수준 확장 BeanPostProcessor 인터페이스 및 BeanFactoryPostProcessor 인터페이스

1. 클래스 수준 수명 주기 콜백

1.1초기화 방법

참조: Springbeanxsdinit-method

init-method는 Spring구성 파일에서 Bean을 선언할 때 구성하는 항목입니다. init-method 구성 항목의 값은 클래스의 매개변수 없는 메서드이지만 예외가 발생할 수 있습니다. 이 메소드는 Spring 컨테이너가 객체를 인스턴스화하고 속성 값을 설정한 후에 호출됩니다. init-method가 구현할 수 있는 기능은 InitializingBean 인터페이스 및 PostConstruct 주석과 일치합니다

Spring 구성 파일 및 테스트 클래스는 다음과 같습니다.

<bean id = "initMethodBeanService" class="name.liuxi.spring.ext.InitMethodBeanService" init-method="init">
   <property name="f2" value="2"/>
</bean>

테스트 수업은 다음과 같습니다:

public class InitMethodBeanService {
	private static Integer f1;
	private Integer f2;
	static {
		f1 = 1;
		System.out.println("InitMethodBeanService static block execute...");
	}
	public InitMethodBeanService(){
		System.out.println("InitMethodBeanService construct method execute...");
	}
	public void init(){
		System.out.println("InitMethodBeanService init method execute...");
	}
	public Integer getF2() {
		return f2;
	}
	public void setF2(Integer f2) {
		this.f2 = f2;
		System.out.println("InitMethodBeanService setF2 method execute...");
	}
}

실행 결과는 다음과 같이 출력됩니다:

InitMethodBeanService static block execute...
InitMethodBeanService construct method execute...
InitMethodBeanService setF2 method execute...
InitMethodBeanService init method execute...
test method execute...

1.2Bean 인터페이스 초기화

참고: Spring 공식 문서 beans-factory-lifecycle-initializingbean

InitializingBean 인터페이스는 Spring 컨테이너가 객체를 인스턴스화하고 속성 값을 설정한 후에 호출되는 afterPropertiesSet 메서드를 선언합니다. 위의 init-method에 의해 구현된 함수는 일관성이 있으므로 Spring에서는 InitializingBean 인터페이스 사용을 권장하지 않습니다.

예제는 비교적 간단하므로 여기에 나열하지 않겠습니다

1.3PostConstruct 주석

번역: Spring 공식 문서 beans-postconstruct-and-predestroy-annotations

@PostConstruct 주석은 init-method 및 InitializingBean 인터페이스

@PostConstruct
public void postConstruct(){
  System.out.println("PostConstructService postConstruct method execute...");
}

와 동일한 효과를 갖는 수명 주기 콜백 메서드입니다. 위의 세 가지 수명 주기 콜백 메서드 init-method, InitializingBean 인터페이스 및 @PostConstruct 주석을 요약합니다

1. 모두 단일 클래스의 인스턴스화 후 처리입니다

2. 클래스가 인스턴스화되고 멤버 변수가 주입된 후 실행 시간이 호출됩니다

3. init-method의 경우 Spring 구성 파일의 beans 요소에서 기본 초기화 방법을 구성할 수도 있습니다. 구성 항목은 default-init-method

입니다. 4. 위 세 가지 방법으로 구성된 초기화 방법이 다를 경우 실행 순서는 다음과 같습니다. @PostConstruct 주석 방법 –>InitializingBean의 afterPropertiesSet->init-method 방법 세 가지 방법으로 구성된 방법이 동일한 경우 메소드는 한 번만 실행됩니다(Spring 공식 문서 beans-factory-lifecycle-combined- effect 참조)

5. 초기화 콜백 메소드가 있고, 그에 상응하는 소멸 콜백 메소드도 있습니다. @PostConstruct 주석 메서드 ->InitializingBean의 afterPropertiesSet->init-method 메서드는 각각 @PreDestroy 주석 메서드->DisposableBean의 destroy->destroy-method 메서드

에 해당합니다.

2. 컨테이너 레벨 확장 번역: Spring 공식 문서 3.8ContainerExtensionPoints

일반적인 상황에서 개발자는 SpringIOC 컨테이너를 확장하기 위해 ApplicationContext의 하위 클래스를 사용자 정의할 필요가 없습니다. SpringIOC 컨테이너는 외부에 노출된 일부 인터페이스를 통해 SpringIOC 컨테이너를 확장할 수 있습니다.

2.1BeanPostProcessor 인터페이스

2.1.1Bean 인스턴스 초기화 후처리기와 후처리기 체인

BeanPostProcessor 인터페이스는 인스턴스를 초기화한 후 일부 논리적 처리에 사용되며 컨테이너의 모든 인스턴스에 대해 처리되는 postProcessBeforeInitialization 및 postProcessAfterInitialization이라는 두 가지 컨테이너 수준 콜백 메서드를 정의합니다. BeanPostProcessor 인터페이스를 구현하는 클래스를 Bean 인스턴스 초기화 후처리기라고 합니다.

여러 인스턴스 초기화 후처리기가 Spring IOC 컨테이너에 통합된 경우 이러한 후처리기의 컬렉션을 Bean 인스턴스 초기화 후처리기 체인이라고 합니다.

postProcessBeforeInitialization方法在类实例化且成员变量注入完成之后执行,初始化方法(例如InitializingBean的afterPropertiesSet方法)之前执行

postProcessAfterInitialization方法在类实例化且成员变量注入完成之后执行,初始化方法(例如InitializingBean的afterPropertiesSet方法)之后执行

总结:

1.实例初始化后处理器多用于对实例的一些代理操作。Spring中一些使用到AOP的特性也是通过后处理器的方式实现的。

2.实例初始化后处理器链是多个后处理器,就会有执行顺序的问题,可以通过实现Ordered接口,指定后处理的执行顺序,Ordered接口声明了getOrder方法,方法返回值越小,后处理的优先级越高,越早执行。

3.在通过实现BeanPostProcessor接口自定义实例初始化后处理器的时候,建议也实现Ordered接口,指定优先级。

4.这些后处理器的作用域是当前的SpringIOC容器,即后处理器被声明的SpringIOC容器。对于有层次结构的SpringIOC容器,实例初始化后处理器链不会作用于其他容器所初始化的实例上,即使两个容器在同一层次结构上。

5.实例初始化后处理器的实现类只需要和普通的被Spring管理的bean一样声明,SpringIOC容器就会自动检测到,并添加到实例初始化后处理器链中。

6.相对于自动检测,我们也可以调用ConfigurableBeanFactory的addBeanPostProcessor方法,以编程的方式将一个实例初始化后处理器添加到实例初始化后处理器链中。这在需要判定添加条件的场景下比较实用。这种编程式的方式会忽略到实现的Ordered接口所指定的顺序,而会作用于所有的被自动检测的实例初始化后处理器之前。

2.1.2bean实例初始化后处理器与AOP

BeanPostProcessor是一个特殊的接口,实现这个接口的类会被作为Spring管理的bean的实例的后处理器。因此,在Spring应用上下文启动的一个特殊阶段,会直接初始化所有实现了BeanPostProcessor接口的实例,以及该实例所引用的类也会被实例化。然后作为后处理器应用于其他普通实例。

由于AOP的自动代理是以实例化后处理器的方式实现的,所以无论是bean实例初始化后处理器链实例还是其引用的实例,都不能被自动代理。因而,不要在这些实例上进行切面织入。(对于这些实例,会产生这样的日志消息:“类foo不能被所有的实例化后处理器链处理,即不能被自动代理”)。

注意:当实例化后处理器以autowiring或@Resource的方式引用其他bean,Spring容器在以类型匹配依赖注入的时候,可能会注入非指定的bean(例如:实例化后处理器实现类以Resource方式依赖bean,若set方法和被依赖的bean的名称一致或者被依赖bean未声明名称,则依赖注入会以类型匹配的方式注入,此时可能会注入非指定的bean)。这也会导致自动代理或其他方式的实例化后处理器处理失败。

2.1.3bean实例初始化后处理器示例

public class BeanPostProcessorService implements BeanPostProcessor {
	@Override
	  public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
		System.out.println("BeanPostProcessorService postProcessAfterInitialization method execute... ");
		return o;
	}
	@Override
	  public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
		System.out.println("BeanPostProcessorService postProcessBeforeInitialization method execute... ");
		return o;
	}
}

2.2BeanFactoryPostProcessor接口

2.2.1beanfactory后处理器

通过实现BeanFactoryPostProcessor接口,可以读取容器所管理的bean的配置元数据,在bean完成实例化之前进行更改,这些bean称之为beanfactory后处理器。

BeanFactoryPostProcessors与BeanPostProcessor接口的异同点:

相同点:

都是容器级别的后处理器

都可配置多个后处理器,并通过实现Ordered接口,指定执行顺序

都是针对接口声明的容器中所管理的bean进行处理,在有层级结构的容器中,不能处理其他容器中的bean,即使两个容器是同一层次

都是只需要在容器中和普通bean一样声明,容器会自动检测到,并注册为后处理器

会忽略延迟初始化属性配置

不同点:

BeanFactoryPostProcessors接口在bean**实例化前处理bean的配置元数据,BeanPostProcessor接口在bean实例化后处理bean的实例**

BeanFactoryPostProcessors接口也能通过BeanFactory.getBean()方法获取bean的实例,这样会引起bean的实例化。由于BeanFactoryPostProcessors后处理器是在所有bean实例化之前执行,通过BeanFactory.getBean()方法会导致提前实例化bean,从而打破容器标准的生命周期,这样可能会引起一些负面的影响(例如:提前实例化的bean会忽略bean实例化后处理器的处理)。

2.2.2Spring内置及自定义beanfactory后处理器

Spring内置了一些beanfactory后处理器(例如:PropertyPlaceholderConfigurer和PropertyOverrideConfigurer)。同时也支持实现BeanFactoryPostProcessor接口,自定义beanfactory后处理器。下面说说Spring内置的两个后处理器和自定义后处理器。

PropertyPlaceholderConfigurer

Spring为了避免主要的XML定义文件的修改而引起的风险,提供了配置分离,可以将一些可能变更的变量配置到属性配置文件中,并在XML定义文件中以占位符的方式引用。这样,修改配置只需要修改属性配置文件即可。PropertyPlaceholderConfigurer用于检测占位符,并替换占位符为配置属性值。示例如下:

PropertyPlaceholderConfigurer通过jdbc.properties属性配置文件,在运行时,将dataSource这个bean中数据库相关信息的属性占位符替换成对应的配置值。

XML配置如下:

<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
  <property name="locations" value="classpath:com/foo/jdbc.properties"/>
</bean>
<bean id="dataSource" destroy-method="close"
    class="org.apache.commons.dbcp.BasicDataSource">
  <property name="driverClassName" value="${jdbc.driverClassName}"/>
  <property name="url" value="${jdbc.url}"/>
  <property name="username" value="${jdbc.username}"/>
  <property name="password" value="${jdbc.password}"/>
</bean>

属性配置文件jdbc.properties如下:

jdbc.driverClassName=org.hsqldb.jdbcDriver
jdbc.url=jdbc:hsqldb:hsql://production:9002
jdbc.username=sa
jdbc.password=root

PropertyPlaceholderConfigurer不仅支持属性配置文件的读取,也支持读取系统属性。通过systemPropertiesMode属性值可配置读取优先级。各种取值说明如下:

0:不读取系统属性

1:若引用的属性配置文件中未检索到对应占位符的配置,则读取系统属性。默认为1

2:先读取系统属性,再读取引用的属性配置文件。这种配置可能导致系统属性覆盖配置文件。

PropertyOverrideConfigurer

PropertyOverrideConfigurer类可以通过引用属性配置文件,直接给容器中的bean赋值。当一个bean的属性被多个PropertyOverrideConfigurer类实例赋值时,最后一个的值会覆盖前面的。

还是以上面给上面的dataSource的bean赋值为例:

PropertyOverrideConfigurer类对属性配置文件的引用使用一个新的方式,如下:

<context:property-override location="classpath:override.properties"/>

override.properties属性配置文件的属性的命名规则和上面不同(上面例子中需要保证属性名和占位符一致),命名规则是beanName.property

dataSource.driverClassName=com.mysql.jdbc.Driver
dataSource.url=jdbc:mysql:mydb
dataSource.username=sa
dataSource.password=root

支持复合属性的赋值,但是要保证引用被赋值属性的对象非空
例如:foo.fred.bob.sammy=123
自定义bean factory后处理器

自定义bean factory后处理器就是实现BeanFactoryPostProcessor接口,完成对Spring容器管理的bean的配置元数据进行修改。例如:修改类属性注入的值,示例如下:

定义一个用户类UserBean

public class UserBean {
	private String userName;
	public String getUserName() {
		return userName;
	}
	public void setUserName(String userName) {
		this.userName = userName;
	}
}

Spring XML配置文件配置用户类,并给用户名属性userName注入值haha

<bean class="name.liuxi.spring.ext.BeanFactoryPostProcessorService"/>
<bean id="user" class="name.liuxi.spring.ext.UserBean">
   <property name="userName" value="haha"/>
</bean>

下面是自定义的bean factory后处理器,修改属性userName的值为heihei

public class BeanFactoryPostProcessorService implements BeanFactoryPostProcessor {
  @Override
  public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
    System.out.println("BeanFactoryPostProcessorService postProcessBeanFactory method execut...");
    BeanDefinition bd = beanFactory.getBeanDefinition("user");
    MutablePropertyValues pv = bd.getPropertyValues();
    if(pv.contains("userName"))
    {
      pv.addPropertyValue("userName", "heihei");
    }
  }
}

相信看了本文案例你已经掌握了方法,更多精彩请关注php中文网其它相关文章!

推荐阅读:

AngularJS实现猜数字小游戏

vue实现键盘效果

위 내용은 Spring 수명주기 및 컨테이너 확장 사용법에 대한 자세한 설명의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
본 글의 내용은 네티즌들의 자발적인 기여로 작성되었으며, 저작권은 원저작자에게 있습니다. 본 사이트는 이에 상응하는 법적 책임을 지지 않습니다. 표절이나 침해가 의심되는 콘텐츠를 발견한 경우 admin@php.cn으로 문의하세요.