Spring探索(一):IoC容器之BeanFactory

1.Spring框架概述
Spring框架倡导基于POJO(Plain Old Java Object,简答Java对象)的轻量级开发理念,从实际出发,立足于最基础的POJO.

2.什么是IoC?
Inversion of Control,控制反转,DI(Dependency Injection)依赖注入
从对象绑定方式的角度看,我们不再主动的去获取依赖的对象,而是交由容器给我们注入进来,对象间的各种依赖关系的管理统统交给容器.

3.DI的方式
(1)构造方法注入
对象在构造完成之后,即已进入就绪状态,可以马上使用.
(2)setter方法注入
setter方法可以被继承,允许设置默认值.

4.掌管大局的IoC Service Provider
将业务对象绑定一起的实现方式.
业务对象的构建管理 + 业务对象间的依赖绑定

运筹帷幄的秘密-IoC Service Provider如何管理对象间的依赖关系?
直接编码的方式
配置文件方式,如描述性较强的XML文件
元数据方式,如Google Guice,基于注解

5.Spring的IoC容器之BeanFactory
Spring提供了两种类型的容器:BeanFactory和ApplicationContext
BeanFactory:基础类型的IoC容器,提供完整的IoC服务支持.如果没有特殊指定,默认采用延迟初始化策略(lazy-load,懒加载),在第一次使用对象的时候,才对对象进行初始化以及依赖注入等操作.所以,相对来说,容器启动初期速度较快,所需资源有限.
ApplicationContext:在BeanFactory的基础上构建,是相对比较高级的容器实现.ApplicationContext容器所管理的对象,在该类型容器启动后,默认全部初始化并绑定完成.所以,相对BeanFactory来说,启动时间会长些,系统资源要求多些.

BeanFactory的对象注册与依赖绑定方式
Spring中,把Beanfactory需要使用的对象注册和依赖绑定信息称为Configuration Metadata.
BeanDefinition:Sring容器中的每一个受管对象都有一个BeanDefinition实例与之对应,该BeanDefinition实例负责保存对象的所有必要信息,
包括其对应的Class,是否为抽象类等.RootBeanDefinitin和ChildBeanDefinition是两个主要的实现类.
BeanDefinitionRegistry:存储BeanDefinition

外部配置文件:
Spring的IoC容器支持两种配置文件格式:properties和xml文件.
BeanDefinitionReader类:用于定义抽象外部配置文件的读取方式,
比如XmlBeanDefinitionReader类用于读取xml格式的配置文件,并解析各种标签,装配信息映射到BeanDefinition,
然后将映射后的BeanDefinition注册到BeanDefinitionRegistry(这里是DefaultListableBeanFactory),再由BeanDefinitionRegistry完成Bean的注册和加载.

注解方式:基于注解的依赖注入方式
@Autowired @Component classpath-scanning

除了可以通过配置明确的指定bean之间的依赖关系,Spring还提供了根据bean定义的某些特点将相互依赖的某些bean直接自动绑定的功能。
Spring提供了5种自动绑定的方式:no(默认的自动绑定方式,完全依赖手工配置),byName,byType,contructor,autodetect(byType和contructor方式的结合)

Spring中的4种类型的依赖检查dependency-check:
(1)no:默认值,不做依赖检查
(2)simple:对简单属性类型以及相关的Collection进行依赖检查
(3)object:只对对象引用类型进行依赖检查
(4)all:simple和object结合

lazy-init
与Beanfactory不同,ApplicationContext在容器启动的时候,就会马上对所有的scope为"singleton"的bean进行实例化操作.
这样做的好处是可以在容器启动时,就第一时间发现问题.
如果不想这样,就给bean添加属性lazy-inti=true,但这也并不保证该bean最终可以lazy-init,因为如果存在not-lazy-init的bean依赖该bean,
则按照依赖决计的顺序,容器还是会首先实例化该lazy-init-bean,然后再实例化not-lazy-init-bean.

bean的Scope
BeanFactory:对象生命周期管理
bean的scope类型:singleton(默认值),prototype,request,session,global,后3种类型只能在web应用中使用.
可以从以下两个角度看待singleton的bean:
对象实例数量:scope=singleton的bean,在一个容器中只存在一个共享实例,所有对该类型bean的依赖都引用这一单一实例.
对象存活时间:scope=singleton的bean,从容器启动,到它第一次被请求而实例化开始,只要容器不销毁或退出,该类型bean的单一实例就会一直存活.
在这里插入图片描述
scope=prototype的bean,容器在接到该类型对象请求的时候,会每次都重新生成一个新的对象实例给调用方,之后,就任由这个对象实例自生自灭了.调用方需要自己负责该实例的后继生命周期的管理,包括该实例的销毁.
在这里插入图片描述

自定义scope类型
org.springframework.beans.factory.config.CustomScopeConfigurer:统一注册自定义scope

工厂方法与FactoryBean
(1)静态工厂方法

 public class StaticBarFactory{
	public static BarInterface getInstance(FooBar foobar){
		return new BarInterfaceImpl(); 
}

XML配置:

<bean id="fooBar" class="...FoorBar"/>
<bean id="bar" class="...StaticBarFactory" factory-method="getInstance">
	<constructor-arg>
		<ref bean="foorBar"/>
	</constructor-arg>
</bean>

(2)非静态工厂方法(Instance Factory Method)

public class InstanceBarFactory{
	public BarInterface getInstance(FooBar foobar){
		return new BarInterfaceImpl(); 
}

XML配置:

<bean id="barFactory" class="...InstanceBarFactory"/>
<bean id="bar" factory-bean="barFactory" factory-method="getInstance"/>

FactoryBean
FactoryBean是Spring提供的一种可以扩展容器对象实例化逻辑的接口.主语是Bean,定语是Factory,也就是说,它本身与其他注册到容器的对象一样,只是一个Bean而已,只不过,这种类型的Bean本身就是生产对象的工厂.
当某些对象的实例化过程过于烦琐,通过XML配置过于复杂,使我们宁愿使用java代码来完成这个实例化过程的时候,或者某些第三方库不能直接注册到Spring容器的时候,就可以实现org.springframework.beans.factory.FactoryBean接口,给出自己的对象实例化逻辑代码.

import org.joda.time.DateTime;
public class NextDayDisplayer{
	private DateTime dateOfNextDay;
	setter...
}

需求:我们想dateOfNextDay每次得到的日期都是第二天.

 import org.joda.time.DateTime;
 import org.springframework.beans.factory.FactoryBean;
 
 public class NextDateFactoryBean implements FactoryBean<DateTime>{
	@Override
	public DateTime getObject() throws Exception{
		return new DateTime().plusDays(1);
	}
   
   public Class<?> getObjectType(){
		return DateTime.class;
	}

	public boolean isSingleton() {
		return false;
	}
}

XML配置:

<bean id="nextDayDisplayer" class="...NextDayDisplayer">
	<property>
		<ref bean="nextDate">
	</property>
<bean/>

<bean id="nextDate" class="...NextDateFactoryBean"/>

FactoryBean类型的bean定义,通过正常的id引用,容器返回的是FactoryBean所生产的对象类型,即getObject()返回的结果,而非FactoryBean对象本身.如果一定要取得FactoryBean本身的话,可以通过Bean定义的id之前加前缀&.

偷梁换柱之术

public class UserService { }

public class BizService {
    private UserService userService;

    public UserService getUserService() {
        return userService;
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void persistUserService(){
        System.out.println("persist bean:" + getUserService());
    }
}
	<bean id="userService" class="com.hong.service.UserService" scope="prototype"/>

	<bean id="bizService" class="com.hong.service.BizService">
		<property name="userService">
			<ref bean="userService"/>
		</property>
	</bean>
public class TestMain {

    private BeanFactory container;

    @Test
    public void test0(){
        BizService bizService = (BizService) container.getBean("bizService");
        bizService.persistUserService();
        bizService.persistUserService();
    }

    @Before
    public void before(){
        container = new XmlBeanFactory(new ClassPathResource("spring-context.xml"));
    }
}

打印结果:
persist bean:com.hong.service.UserService@15530b9
persist bean:com.hong.service.UserService@15530b9

虽然我们将UserService的scope设置为prototype类型的,但实际测试发现,多次调用,返回的是同一个实例.这是为什么呢?实际上,问题不是出在scope是否为prototype,而是出在实例的取得方式上面.当容器将一个UserService实例注入BizService后,BizService就会一直持有这个UserService实例的引用,换句话说,第一个UserService实例注入后,BizService再也没有重新向容器申请新的实例.所以,容器也不会重新为其注入新的UserService实例.

(1)方法注入(Method injection)
方法声明需要符合以下定义:

<public|protected> [abstract] <return-type> theMethodName(no-arguments);

也就是说,该方法必须能够被子类实现或者覆写,因为容器会为我们要进行方法注入的对象使用Cglib动态生成一个子类实现,从而替代当前对象.

	<bean id="userService" class="com.hong.service.UserService" scope="prototype"/>

	<bean id="bizService" class="com.hong.service.BizService">
		<!--通过<lookup-method>的name属性指定需要注入的方法名,bean属性指定需要注入的对象,当getUserService方法被调用的时候,容器可以每次返回一个新的UserService实例-->
		 <lookup-method name="getUserService" bean="userService"/>
	</bean>

这时,再次运行TestMain.test0,打印结果如下:
persist bean:com.hong.service.UserService@1970963
persist bean:com.hong.service.UserService@1f8bee4

殊途同归
除了使用方法注入来达到"每次调用都让容器返回新的对象实例"的目的,使用以下方式同样可以:
(1)使用BeanFactoryAware接口
让BizService拥有一个BeanFactory的引用,保证在BizService.getUserService()中,每次都调用BeanFactory.getBean(“userService”),就可以得到新的UserService实例.
Spring容器在实例化BeanFactoryAware的实现类的过程中会自动将容器本身注入该bean.这样,该bean就持有了它所处的BeanFactory的引用.

package org.springframework.beans.factory;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.Aware;
import org.springframework.beans.factory.BeanFactory;

public interface BeanFactoryAware extends Aware {
    void setBeanFactory(BeanFactory var1) throws BeansException;
}

改造BizService,实现BeanFactoryAware.

public class BizService implements BeanFactoryAware{
    private UserService userService;
    private BeanFactory beanFactory;

    public UserService getUserService() {
        return (UserService) beanFactory.getBean("userService");
    }

    public void setUserService(UserService userService) {
        this.userService = userService;
    }

    public void persistUserService(){
        System.out.println("persist bean:" + getUserService());
    }

    @Override
    public void setBeanFactory(BeanFactory beanFactory) throws BeansException {
        this.beanFactory = beanFactory;
    }
}
	<bean id="userService" class="com.hong.service.UserService" scope="prototype"/>
	<bean id="bizService" class="com.hong.service.BizService"/>

(2)使用ObjectFactoryCreatingFactoryBean
ObjectFactoryCreatingFactoryBean是Spring提供的一个FactoryBean实现,同时该类也间接实现了BeanFactoryAware接口.使用它的好处是隔离了客户端对象对BeanFactory的直接引用.

package com.hong.service;

import org.springframework.beans.factory.ObjectFactory;

/**
 * Created by John on 2018/10/26.
 */
public class BizService {
    private ObjectFactory userServiceBeanFactory;

    public UserService getUserService() {
        return (UserService) userServiceBeanFactory.getObject();
    }

    public void setUserServiceBeanFactory(ObjectFactory userServiceBeanFactory) {
        this.userServiceBeanFactory = userServiceBeanFactory;
    }

    public void persistUserService(){
        System.out.println("persist bean:" + getUserService());
    }

}
	<bean id="userService" class="com.hong.service.UserService" scope="prototype"/>

	<bean id="userServiceBeanFactory" class="org.springframework.beans.factory.config.ObjectFactoryCreatingFactoryBean">
		<property name="targetBeanName">
			<idref bean="userService"/>
		</property>
	</bean>

	<bean id="bizService" class="com.hong.service.BizService">
		<property name="userServiceBeanFactory">
			<ref bean="userServiceBeanFactory"/>
		</property>
	</bean>

也可以使用ServiceLoaderFactoryBean替代ObjectFactoryCreatingFactoryBean.

容器背后的秘密
Spring的IoC容器实现可以分为两个阶段:容器启动阶段和bean实例化阶段.
其中,容器启动阶段相当于根据图纸装配生产线,而bean的实例化阶段就是使用装配好的生产线来生成具体的产品了.
在这里插入图片描述
在这里插入图片描述

插手"容器的启动"
容器的扩展机制:org.springframework.beans.factory.config.BeanFactoryPostProcessor
Spring中常用的BeanFactoryPostProcessor实现:
(1)org.springframework.beans.factory.config.PropertyPlaceholderConfigurer
该类允许我们在XML配置文件中使用占位符(PlaceHolder),并将这些占位符所代表的资源单独配置到简单的properties文件中来加载.

package com.hong.entity;

/**
 * Created by John on 2018/10/27.
 */
public class DataSourceConfig {
    private String userName;
    private String password;

   getter/setter()...
   
    @Override
    public String toString() {
        return "DataSourceConfig{" +
                "userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                '}';
    }
}
	<bean id="dataSource" class="com.hong.entity.DataSourceConfig">
		<property name="userName">
			<value>${dataSource.userName}</value>
		</property>
		<property name="password">
			<value>${dataSource.password}</value>
		</property>
	</bean>
	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location" value="placeholder-config.properties"/>
	</bean>

placeholder-config.properties

#properties文件中的key要满足beanName.propertyName=value(beanName通常就是XML配置中的id)
dataSource.userName=root
dataSource.password=123456
public class TestMain2 {

    private ClassPathXmlApplicationContext container;

    @Before
    public void before(){
        container = new ClassPathXmlApplicationContext("spring-context.xml");
    }

    @Test
    public void test0(){
        DataSourceConfig dataSourceConfig = (DataSourceConfig) container.getBean("dataSource");
        System.out.println(dataSourceConfig);//DataSourceConfig{userName='root', password='123456'}
    }
}

(2)org.springframework.beans.factory.config.PropertyOverrideConfigurer
可以该类对容器中配置的任何你想处理的bean定义的property信息进行覆盖替换.

package com.hong.entity;

/**
 * Created by John on 2018/10/27.
 */
public class DataSourceConfig {
    private String userName;
    private String password;
    private Integer maxActive;
  
    getter/setter()...
   
    @Override
    public String toString() {
        return "DataSourceConfig{" +
                "userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", maxActive=" + maxActive +
                '}';
    }
}

propertyoverride-config.properties

dataSource.maxActive=200
	<bean id="dataSource" class="com.hong.entity.DataSourceConfig">
	<property name="userName">
		<value>${dataSource.userName}</value>
	</property>
	<property name="password">
		<value>${dataSource.password}</value>
	</property>
	<property name="maxActive">
		<value>100</value>
	</property>
	</bean>

	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location" value="placeholder-config.properties"/>
	</bean>

	<bean class="org.springframework.beans.factory.config.PropertyOverrideConfigurer">
		<property name="location" value="propertyoverride-config.properties"/>
	</bean>
 @Test
    public void test0(){
        DataSourceConfig dataSourceConfig = (DataSourceConfig) container.getBean("dataSource");
        System.out.println(dataSourceConfig);//DataSourceConfig{userName='root', password='123456', maxActive=200}
    }

配置在properties文件中的内容通常都以明文表示,PropertyOverrideConfigurer和PropertyPlaceholderConfigurer的父类PropertyResourceConfigurer提供了一个protected类型的方法convertPropertyValue允许子类覆盖这个方法对相应的配置项进行转换,如对加密后的字符串解密之后再覆盖到相应的bean定义中,该方法定义如下:

protected String convertPropertyValue(String originalValue) {
        return originalValue;
    }

(3)org.springframework.beans.factory.config.CustomEditorConfigurer
因为XML装载的信息都是String类型的,自然容器从XML中读取的都是字符串形式,然而最终的应用程序却是由各种类型的对象构成的,Spring内部通过JavaBean的PropertyEditor(java.beans.PropertyEditor)来帮助进行Spring到其他类型的转换工作.但当我们需要指定的类型不在Spring的PropertyEditor之列时,就需要给出针对这种类型的PropertyEditor实现,并通过CustomEditorConfigurer告知容器,以便容器在适当的时机使用适当的PropertyEditor.
场景:对yyyy/mm/dd格式的日期转换为Date类型.

 package com.hong.entity;

import java.time.LocalDate;

/**
 * Created by John on 2018/10/26.
 */
public class User {
    private Long id;
    private Integer age;
    private String name;
    private LocalDate birthday;

 	getter/setter()...
 
    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", age=" + age +
                ", name='" + name + '\'' +
                ", birthday=" + birthday +
                '}';
    }
}
import org.springframework.beans.PropertyEditorRegistrar;
import org.springframework.beans.PropertyEditorRegistry;

import java.beans.PropertyEditor;

/**
 * Created by John on 2018/10/27.
 */
public class DatePropertyEditorRegister implements PropertyEditorRegistrar {
    private PropertyEditor propertyEditor;
    
    @Override
    public void registerCustomEditors(PropertyEditorRegistry propertyEditorRegistry) {
        propertyEditorRegistry.registerCustomEditor(java.time.LocalDate.class,getPropertyEditor());
    }

    public PropertyEditor getPropertyEditor() {
        return propertyEditor;
    }

    public void setPropertyEditor(PropertyEditor propertyEditor) {
        this.propertyEditor = propertyEditor;
    }
}
package com.hong.config;

import java.beans.PropertyEditorSupport;
import java.time.LocalDate;
import java.time.format.DateTimeFormatter;
import java.time.temporal.TemporalAccessor;

/**
 * Created by John on 2018/10/27.
 */
public class DatePropertyEditor extends PropertyEditorSupport {
    private String datePattern;

    @Override
    public void setAsText(String text) throws IllegalArgumentException {
        DateTimeFormatter dateTimeFormatter = DateTimeFormatter.ofPattern(datePattern);
        TemporalAccessor temporalAccessor = dateTimeFormatter.parse(text);
        LocalDate localDate = LocalDate.from(temporalAccessor);
        setValue(localDate);
    }

    public String getDatePattern() {
        return datePattern;
    }

    public void setDatePattern(String datePattern) {
        this.datePattern = datePattern;
    }
}
	<bean id="user" class="com.hong.entity.User">
		<property name="id" value="123"/>
		<property name="age" value="28"/>
		<property name="name" value="wh"/>
		<property name="birthday" value="1990/12/27"/>
	</bean>

	<bean class="org.springframework.beans.factory.config.CustomEditorConfigurer">
		<property name="propertyEditorRegistrars">
			<list>
				<ref bean="datePropertyEditorRegister"/>
			</list>
		</property>
	</bean>

	<bean id="datePropertyEditorRegister" class="com.hong.config.DatePropertyEditorRegister">
		<property name="propertyEditor">
			<ref bean="datePropertyEditor"/>
		</property>
	</bean>

	<bean id="datePropertyEditor" class="com.hong.config.DatePropertyEditor">
		<property name="datePattern" value="yyyy/MM/dd"/>
	</bean>
    @Test
    public void test1(){
        User user = (User) container.getBean("user");
        System.out.println(user); //User{id=123, age=28, name='wh', birthday=1990-12-27}
    }

了解Bean的一生
在这里插入图片描述

(1)Bean的实例化与BeanWrapper
容器在内部实现的时候,采用策略模式"来决定以何种方式初始化bean实例.通常,可以通过反射或者CGLIB动态字节码生成来初始化相应的bean实例或动态生成其子类.
org.springframework.beans.factory.support.InstantiationStrategy定义是实例化策略的抽象接口,其直接子类SimpleInstantiationStrategy实现类简单的对象实例化功能,可以通过反射来实例化对象实例,但不支持方法注入方式的对象实例化.CglibSubclassingInstantiationStrategy继承自SimpleInstantiationStrategy,可以动态生成某个类的子类,支持方法注入.容器内部默认采用的是CglibSubclassingInstantiationStrategy.
org.springframework.beans.BeanWrapper通常在Spring框架内部使用,它有一个实现类BeanWrapperImpl,其作用是对某个bean进行"包裹",然后对这个包裹的bean进行操作,比如设置或者获取bean的相应属性值.
容器在解析bean完成bean实例化时,并不是直接返回构造完成的对象实例,而是以BeanWrapper对构造完成的实例进行包裹,返回相应的BeanWrapper实例.

各色的Aware接口
当对象实例化完成并且相关属性和依赖设置完成后,Spring容器会检查当前实例是否实现了一系列以Aware命名结尾的接口定义,如果是,则将这些Aware接口定义中的规定的依赖注入给当前实例.
这些Aware接口分为如下几类:
(1)org.springframework.beans.factory.BeanNameAware
(2)org.springframework.beans.factory.BeanClassLoaderAware
(3)org.springframework.beans.factory.BeanFactoryAware
以上Aware接口只是针对BeanFactory类型的容器而言,对于ApplicationContext类型容器,使用的是BeanPostProcessor方式.
(1)org.springframework.context.ResourceLoaderAware
(2)org.springframework.context.ApplicationContextAware

BeanPostProcessor
BeanPostProcessor是存在于对象实例化阶段,而BeanFactoryPostProcessor则是存在于容器启动阶段.

package org.springframework.beans.factory.config;

import org.springframework.beans.BeansException;

public interface BeanPostProcessor {
    Object postProcessBeforeInitialization(Object var1, String var2) throws BeansException;

    Object postProcessAfterInitialization(Object var1, String var2) throws BeansException;
}

通常比较常用的使用BeanPostProcessor的场景,是处理标记接口(Marker Interface)实现类或者为当前对象提供代理实现,它是容器提供的对象实例化阶段的强有力的扩展点.

自定义BeanPostProcessor
假设数据库连接密码是加密保存在properties文件中的,现在希望容器在设置配置类的密码属性时注入进来的是解密后的密码,How to do!

/**
 * 密码解密标记接口
 * Created by John on 2018/10/28.
 */
public interface PasswordDecodable {
    String getEncodedPassword();
    void setDecodedPassword(String password);
}
package com.hong.config;

import com.hong.service.PasswordDecodable;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

/**
 * Created by John on 2018/10/28.
 */
public class PasswordDecodePostProcessor implements BeanPostProcessor {

    @Override
    public Object postProcessBeforeInitialization(Object o, String s) throws BeansException {
        if (o instanceof PasswordDecodable) {
            String encodedPassword = ((PasswordDecodable) o).getEncodedPassword();
            String decodedPassword = decodePassword(encodedPassword);
            ((PasswordDecodable) o).setDecodedPassword(decodedPassword);
        }
        return o;
    }

    private String decodePassword(String encodedPassword){
        //解密密码
        String decodedPassword = encodedPassword.replace("#*123","").trim();
        return decodedPassword;
    }

    @Override
    public Object postProcessAfterInitialization(Object o, String s) throws BeansException {
        return o;
    }
}
package com.hong.entity;

import com.hong.service.PasswordDecodable;

/**
 * Created by John on 2018/10/27.
 */
public class DataSourceConfig implements PasswordDecodable{
    private String userName;
    private String password;
    private Integer maxActive;

    getter/setter()...

    @Override
    public String toString() {
        return "DataSourceConfig{" +
                "userName='" + userName + '\'' +
                ", password='" + password + '\'' +
                ", maxActive=" + maxActive +
                '}';
    }

    @Override
    public String getEncodedPassword() {
        return this.password;
    }

    @Override
    public void setDecodedPassword(String password) {
        this.password = password;
    }
}

placeholder-config.properties

#properties文件中的key要满足beanName.propertyName=value(beanName通常就是XML配置中的id)
dataSource.userName=root
#假设这里的密码加密规则为原密码最后+slat(#*123)
dataSource.password=123456#*123
	<bean id="dataSource" class="com.hong.entity.DataSourceConfig">
	<property name="userName">
		<value>${dataSource.userName}</value>
	</property>
	<property name="password">
		<value>${dataSource.password}</value>
	</property>
	<property name="maxActive">
		<value>100</value>
	</property>
	</bean>

	<bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
		<property name="location" value="placeholder-config.properties"/>
	</bean>
    private ClassPathXmlApplicationContext container;

    @Before
    public void before(){
        container = new ClassPathXmlApplicationContext("spring-context.xml");
    }

    @Test
    public void test0(){
        DataSourceConfig dataSourceConfig = (DataSourceConfig) container.getBean("dataSource");
        System.out.println(dataSourceConfig);//DataSourceConfig{userName='root', password='123456', maxActive=100}
    }

InitializingBean和init-method

package org.springframework.beans.factory;

public interface InitializingBean {
    void afterPropertiesSet() throws Exception;
}

InitializingBean是容器内部广泛使用的一个对象生命周期标识接口,其作用在于,在对象实例化过程调用过"BeanPostProcessor的前置处理"之后,会接着检测当前对象是否实现了InitializingBean接口,如果是,则会调用其afterPropertiesSet方法进一步调整对象实例的状态.

DisposableBean与destroy-method

package org.springframework.beans.factory;

public interface DisposableBean {
    void destroy() throws Exception;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值