一、注解解釋
Spring的@PostConstruct注解在方法上,表示此方法是在Spring實例化該Bean之后馬上執行此方法,之后才會去實例化其他Bean,並且一個Bean中@PostConstruct注解的方法可以有多個。
二、示例代碼
1. spring配置文件
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.0.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-3.0.xsd "> <!-- 引入屬性文件 --> <context:property-placeholder location="classpath:config.properties" /> <!-- 自動掃描dao和service包(自動注入) --> <context:component-scan base-package="com.wbf.bean" /> </beans>
2. Bean1.java
1 package com.wbf.bean; 2 3 import javax.annotation.PostConstruct; 4 5 import org.apache.log4j.Logger; 6 import org.springframework.stereotype.Service; 7 8 @Service("bean1") 9 public class Bean1 { 10 11 private static final Logger log = Logger.getLogger(Bean1.class); 12 13 public Bean1() { 14 log.info(System.currentTimeMillis() + ": Bean1 Constructor"); 15 } 16 17 @PostConstruct 18 public void test() { 19 log.info(System.currentTimeMillis() + ": bean1-->test()"); 20 Bean2.uniqueInstance().test(); 21 22 } 23 24 @PostConstruct 25 public void print() { 26 log.info(System.currentTimeMillis() + ": bean1-->print()"); 27 } 28 }
3. Bean2.java
package com.wbf.bean; import org.apache.log4j.Logger; public class Bean2 { private static final Logger log = Logger.getLogger(Bean2.class); private static Bean2 instance = uniqueInstance(); public static Bean2 uniqueInstance() { if (instance == null) instance = new Bean2(); return instance; } public Bean2() { log.info(System.currentTimeMillis() + ": Bean2 Construtor"); } public void test() { log.info(System.currentTimeMillis() + ": bean2-->test()"); } }
4. Bean3.java
1 package com.wbf.bean; 2 3 import org.apache.log4j.Logger; 4 import org.springframework.stereotype.Service; 5 6 @Service("bean3") 7 public class Bean3 { 8 9 private static final Logger log = Logger.getLogger(Bean3.class); 10 11 public Bean3() { 12 log.info(System.currentTimeMillis() + ": Bean3 Construtor"); 13 } 14 15 }
5. SpringTest.java
1 package com.wbf.bean; 2 3 import org.junit.Test; 4 import org.springframework.context.ApplicationContext; 5 import org.springframework.context.support.ClassPathXmlApplicationContext; 6 7 public class SpringTest { 8 9 @Test 10 public void test() { 11 //加載/解析spring.xml, 得到BeanFactory, 實例化所有IOC容器中的Bean 12 //在實例化每一個Bean之后,如果當前Bean包含@PostConstruct注解的方法則會馬上執行該方法,之后才會去實例化其他的Bean 13 //每一個Bean中可以有多個包含@PostConstruct注解的方法 14 ApplicationContext ac = new ClassPathXmlApplicationContext(new String[]{"classpath:spring.xml"}); 15 } 16 17 }
運行結果:
[org.springframework.context.support.ClassPathXmlApplicationContext]Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@b0f2b2: startup date [Thu Jun 11 11:51:17 CST 2015]; root of context hierarchy [org.springframework.beans.factory.xml.XmlBeanDefinitionReader]Loading XML bean definitions from class path resource [spring.xml] [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer]Loading properties file from class path resource [config.properties] [org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor]JSR-330 'javax.inject.Inject' annotation found and supported for autowiring [org.springframework.beans.factory.support.DefaultListableBeanFactory]Pre-instantiating singletons in org.springframework.beans.factory.support.DefaultListableBeanFactory@1b8dc93: defining beans [org.springframework.beans.factory.config.PropertyPlaceholderConfigurer#0,bean1,bean3,org.springframework.context.annotation.internalConfigurationAnnotationProcessor,org.springframework.context.annotation.internalAutowiredAnnotationProcessor,org.springframework.context.annotation.internalRequiredAnnotationProcessor,org.springframework.context.annotation.internalCommonAnnotationProcessor,org.springframework.context.annotation.internalPersistenceAnnotationProcessor,org.springframework.context.annotation.ConfigurationClassPostProcessor.importAwareProcessor]; root of factory hierarchy [com.wbf.bean.Bean1]1433994678340: Bean1 Constructor [com.wbf.bean.Bean1]1433994678347: bean1-->print() [com.wbf.bean.Bean1]1433994678347: bean1-->test() [com.wbf.bean.Bean2]1433994678348: Bean2 Construtor [com.wbf.bean.Bean3]1433994678348: Bean3 Construtor
從運行結果可以看出Spring在實例化Bean1之后馬上執行了它的@PostConstruct注解的方法print()和test(),之后才去實例化Bean3。其中Bean2沒有被Spring IOC容器管理。
三、補充說明
1.@PostConstruct說明
被@PostConstruct修飾的方法會在服務器加載Servlet(bean)的時候運行,並且只會被服務器調用一次,類似於Serclet的inti()方法。被@PostConstruct修飾的方法會在構造函數之后,init()方法之前運行。
2.@PreDestroy說明
被@PreDestroy修飾的方法會在服務器卸載Servlet(bean)的時候運行,並且只會被服務器調用一次,類似於Servlet的destroy()方法。被@PreDestroy修飾的方法會在destroy()方法之后運行,在Servlet被徹底卸載之前
另外,spring中Constructor、@Autowired、@PostConstruct的順序
其實從依賴注入的字面意思就可以知道,要將對象p注入到對象a,那么首先就必須得生成對象a和對象p,才能執行注入。所以,如果一個類A中有個成員變量p被@Autowried注解,那么@Autowired注入是發生在A的構造方法執行完之后的。
如果想在生成對象時完成某些初始化操作,而偏偏這些初始化操作又依賴於依賴注入,那么久無法在構造函數中實現。為此,可以使用@PostConstruct注解一個方法來完成初始化,@PostConstruct注解的方法將會在依賴注入完成后被自動調用。
Constructor >> @Autowired >> @PostConstruct
舉個例子:
1 public Class AAA{ 2 @Autowired 3 private BBB b; 4 5 public AAA() { 6 System.out.println("此時b還未被注入: b = " + b); 7 } 8 @PostConstruct 9 private void init () { 10 System.out.println("@PostConstruct將在依賴注入完成后被自動調用: b = " + b); 11 } 12 }