1. lazy-Init延遲載入
Bean物件的延遲載入(延遲建立)
ApplicationContext 容器的預設⾏為是在啟動伺服器時將所有 singleton bean 提前進⾏例項化。提前例項化意味著作為初始化過程的⼀部分,ApplicationContext例項會建立並配置所有的singleton bean。
1.1 XML方式開啟延遲載入:
lazy-init="" 配置bean物件的延遲載入 ,true或者false false就是立即載入
<bean id="lazyResult" class="com.lagou.edu.pojo.Result" lazy-init="false"></bean>
我們先來看一下當lazy-init="false"
也就是立即載入的時候:
可以看到,在容器啟動後,getBean之前,lazyResult這個bean已經存在了。
然後我們把lazy-init="true"
,設定為true
然後我們F8往下走一步:
發現出現了lazyResult
1.2 註解開啟延遲載入:
@Lazy:
1.3全域性配置——default-lazy-init="":
在bean的根標籤中:
應用場景:
(1)開啟延遲載入⼀定程度提⾼容器啟動和運轉效能
(2)對於不常使⽤的 Bean 設定延遲載入,這樣偶爾使⽤的時候再載入,不必要從⼀開始該 Bean 就佔⽤資源
2. FactoryBean和BeanFactory
2.1 BeanFactory
容器的頂級介面,定義了容器的一些基礎行為,負責生產和管理Bean的一個工廠,具體使用它下面的子介面型別,比如ApplicationContext
2.2 FactoryBean
spring中的bean有兩種
- 普通bean
- 工廠bean(FactoryBean)
可以生產某一個型別的bean例項(返回給我們),也就是說我們可以藉助於它自定義bean的建立過程。
Bean建立的三種⽅式中的靜態⽅法和例項化⽅法和FactoryBean作⽤類似,FactoryBean使⽤較多,尤其在Spring框架⼀些元件中會使⽤,還有其他框架和Spring框架整合時使⽤
//可以讓我們自定義Bean的建立過程,完成複雜bean定義
public interface FactoryBean<T> {
//返回FactoryBean建立的例項,如果isSingleton返回true,則該例項會放到Spring容器的單例快取池中Map
@Nullable
T getObject() throws Exception;
//返回FactoryBean建立的bean型別
@Nullable
Class<?> getObjectType();
//返回作用域是否單例
default boolean isSingleton() {
return true;
}
}
2.2.1 新建類CompanyFactoryBean,實現FactoryBean介面,並重寫方法:
public class CompanyFactoryBean implements FactoryBean<Company> {
private String companyInfo;//注入公司名稱,地址,規模 以逗號分隔
public void setCompanyInfo(String companyInfo) {
this.companyInfo = companyInfo;
}
@Override
public Company getObject() throws Exception {
//建立複雜物件Company
Company company=new Company();
String[] split = companyInfo.split(",");
company.setName(split[0]);
company.setAddress(split[1]);
company.setScale(Integer.parseInt(split[2]));
return company;
}
@Override
public Class<?> getObjectType() {
//返回bean的型別
return Company.class;
}
@Override
public boolean isSingleton() {
//是否是單例
return true;
}
}
public class Company {
private String name;
private String address;
private int scale;
//省略getset 和toString
}
2.2.2 xml檔案中配置bean
<bean id="companyBean" class="com.lagou.edu.factory.CompanyFactoryBean">
<property name="companyInfo" value="拉鉤,中關村,500"></property>
</bean>
2.2.3 測試
@org.junit.Test
public void test(){
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
Object companyBean = applicationContext.getBean("companyBean");
System.out.println(companyBean);
}
//結果返回的是 Company{name='拉鉤', address='中關村', scale=500}
雖然在xml配置檔案中配置的bean的class="com.lagou.edu.factory.CompanyFactoryBean"
但是返回的Company型別。
如何返回CompanyFactoryBean型別呢?
列印結果為:com.lagou.edu.factory.CompanyFactoryBean@545b995e
3. 後置處理器
Spring提供了兩種後處理bean的擴充套件接⼝,分別為 BeanPostProcessor
和BeanFactoryPostProcessor
,兩者在使⽤上是有所區別的。
⼯⼚初始化(BeanFactory)—> Bean物件
在BeanFactory初始化之後可以使⽤BeanFactoryPostProcessor進⾏後置處理做⼀些事情
在Bean物件例項化(並不是Bean的整個⽣命週期完成)之後可以使⽤BeanPostProcessor進⾏後置處理做⼀些事情
注意:物件不⼀定是springbean,⽽springbean⼀定是個物件
3.1 SpringBean生命週期圖
按照上述描述的列印一下。看看是否一致:
//實現了BeanNameAware、BeanFactoryAware、ApplicationContextAware、InitializingBean,DisposableBean介面
public class Result implements BeanNameAware, BeanFactoryAware, ApplicationContextAware, InitializingBean, DisposableBean {
private String status;
private String message;
//省略getset toString方法
@Override
public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
System.out.println("4.BeanFactoryAware:"+beanFactory);
}
@Override
public void setBeanName(String name) {
System.out.println("3.BeanNameAware:"+name);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
System.out.println("5.ApplicationContextAware:"+applicationContext);
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("7.InitializingBean");
}
public void initMethodTest(){
System.out.println("8.initMethod");
}
@PostConstruct
public void postCoustrcut(){
System.out.println("postCoustrcut");
}
//銷燬之前執行
@PreDestroy
public void preDestroy(){
System.out.println("銷燬之前執行");
}
@Override
public void destroy() throws Exception {
System.out.println("DisposableBean");
}
}
/**
攔截例項化之後的物件(例項化了 並且屬性注入了)
攔截所有的
*/
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
if ("lazyResult".equalsIgnoreCase(beanName)){
System.out.println("MyBeanPostProcessor before");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if ("lazyResult".equalsIgnoreCase(beanName)){
System.out.println("MyBeanPostProcessor After");
}
return bean;
}
}
//XML配置檔案中:
<bean id="lazyResult" class="com.lagou.edu.pojo.Result" init-method="initMethodTest"></bean>
//測試:
@org.junit.Test
public void testBeanLazy(){
ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("classpath:applicationContext.xml");
Object lazyResult = applicationContext.getBean("lazyResult");
System.out.println(lazyResult);
applicationContext.close();
}
列印出: