lazy-Init 延迟加载 ApplicationContext 容器的默认行为是在启动服务器时将所有 singleton bean 提前进行实例化。提前实例化意味着作为初始化过程的一部分,ApplicationContext 实例会创建并配置所有的 singleton bean。
1 2 3 <bean id ="lazyResult" class ="com.lagou.edu.pojo.Result" /> 该bean默认的设置为 <bean id ="lazyResult" class ="com.lagou.edu.pojo.Result" lazy-init ="false" />
lazy-init=”false”,立即加载,表示在spring启动时,立刻进行实例化。如果不想让一个singleton bean 在 ApplicationContext 实现初始化时被提前实例化,那么可以将 lazy-init 设置为true。
1 <bean id ="lazyResult" class ="com.lagou.edu.pojo.Result" lazy-init ="true" />
设置 lazy-init 为 true 的 bean 将不会在 ApplicationContext 启动时提前被实例化,而是第一次向容器通过 getBean 获取 bean 时实例化的。 如果一个设置了立即加载的 bean1,引用了一个延迟加载的 bean2 ,那么 bean1 在容器启动时被实例化,而 bean2 由于被 bean1 引用,所以也被实例化,这种情况也符合延时加载的 bean 在第一次调用时才被实例化的规则。 也可以在容器层次中通过在元素上使用 “default-lazy-init” 属性来控制延时初始化。如下面配置:
1 2 3 4 5 6 7 8 9 10 11 12 <?xml version="1.0" encoding="utf-8" ?> <beans default-lazy-init ="true" xmlns ="http://www.springframework.org/schema/beans" xmlns:context ="http://www.springframework.org/schema/context" xmlns:xsi ="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation =" http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd" ></beans >
如果一个 bean 的 scope 属性为 scope=”pototype” 时,即使设置了 lazy-init=”false”,容器启动时也不会实例化bean,而是调用 getBean 方法实例化的。
FactoryBean Spring 中 Bean 有两种,一种是普通 Bean,一种是工厂 Bean(FactoryBean),FactoryBean 可以生成某一个类型的 Bean 实例,我们可以借助于它自定义 Bean 的创建过程。 Bean 创建的三种方式中的静态方法和实例化方法和 FactoryBean 作用类似,FactoryBean 使用较多,尤其在 Spring 框架一些组件中会使用,还有其他框架和 Spring 框架整合时使用。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 public interface FactoryBean <T> { @Nullable T getObject () throws Exception; @Nullable Class<?> getObjectType(); default boolean isSingleton () { return true ; } }
案例 1 2 3 4 5 6 7 8 9 public class Company { private String name; private String address; private int scale; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 public class CompanyFactoryBean implements FactoryBean <Company> { private final String companyInfo; public CompanyFactoryBean (String companyInfo) { this .companyInfo = companyInfo; } @Override public Company getObject () throws Exception { String[] info = companyInfo.split("," ); Company company = new Company (); company.setName(info[0 ]); company.setAddress(info[1 ]); company.setScale(Integer.parseInt(info[2 ])); return company; } @Override public Class<?> getObjectType() { return Company.class; } @Override public boolean isSingleton () { return true ; } }
xml 配置:
1 2 3 <bean id ="companyBean" class ="com.litianyi.factory.CompanyFactoryBean" > <constructor-arg value ="拉钩,中关村,500" /> </bean >
测试方法:
1 2 3 4 5 6 7 8 9 10 public class IoCTest { @Test public void test () { ApplicationContext applicationContext = new ClassPathXmlApplicationContext ("application-context.xml" ); Object companyBean = applicationContext.getBean("companyBean" ); Object companyBeanFactory = applicationContext.getBean("&companyBean" ); System.out.println(companyBean); System.out.println(companyBeanFactory); } }
结果:
1 2 Company{name='拉钩', address='中关村', scale=500} com.litianyi.factory.CompanyFactoryBean@49070868
后置处理器 Spring 提供了两种后处理 bean 的扩展接口,分别为 BeanPostProcessor 和 BeanFactoryPostProcessor,两者在使用上是有所区别的。
工厂初始化(BeanFactory) –> Bean 对象 在 BeanFactory 初始化之后可以使用 BeanFactoryPostProcessor 进行后置处理做一些事情。 在 Bean 对象实例化(并不是Bean的整个生命周期完成,此时还不是一个 SpringBean)之后可以使用 BeanPostProcessor 进行后置处理做一些事情。
BeanPostProcessor BeanPostProcessor 是针对 Bean 级别的处理,可以针对某个具体的 Bean。
1 2 3 4 5 6 7 8 9 10 11 12 13 public interface BeanPostProcessor { @Nullable default Object postProcessBeforeInitialization (Object bean, String beanName) throws BeansException { return bean; } @Nullable default Object postProcessAfterInitialization (Object bean, String beanName) throws BeansException { return bean; } }
该接口提供了两个方法,分别在Bean的初始化方法前和初始化方法后执行,类似我们在定义bean时,定义了 init-method 所指定的方法。 定义一个类实现了 BeanPostProcessor,默认是会对整个 Spring 容器中所有的 bean 进行处理。如果要对具体的某个 bean 处理,可以通过方法参数判断,两个类型参数分别为Object 和 String,第一个参数是每个bean 的实例,第二个参数是每个 bean 的 name 或者 id 属性的值。所以我们可以通过第二个参数,来判断我们将要处理的具体的 bean。 注意:处理是发生在 Spring 容器的实例化和依赖注入之后。(可以参照 Spring 生命周期)
BeanFactoryPostProcessor BeanFactory 级别的处理,是针对整个 Bean 的工厂进行处理。 典型应用:PropertyPlaceholderConfigurer
1 2 3 4 5 6 @FunctionalInterface public interface BeanFactoryPostProcessor { void postProcessBeanFactory (ConfigurableListableBeanFactory beanFactory) throws BeansException; }
此接口只提供了一个方法,方法参数为 ConfigurableListableBeanFactory,该参数类型定义了一些方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public interface ConfigurableListableBeanFactory extends ListableBeanFactory , AutowireCapableBeanFactory, ConfigurableBeanFactory { void ignoreDependencyType (Class<?> type) ; void ignoreDependencyInterface (Class<?> ifc) ; void registerResolvableDependency (Class<?> dependencyType, @Nullable Object autowiredValue) ; boolean isAutowireCandidate (String beanName, DependencyDescriptor descriptor) throws NoSuchBeanDefinitionException; BeanDefinition getBeanDefinition (String beanName) throws NoSuchBeanDefinitionException; Iterator<String> getBeanNamesIterator () ; void clearMetadataCache () ; void freezeConfiguration () ; boolean isConfigurationFrozen () ; void preInstantiateSingletons () throws BeansException; }
其中有个方法名为 getBeanDefinition 的方法,我们可以根据此方法,找到我们定义 bean 的 BeanDefinition对象。然后我们可以对定义的属性进行修改,以下是BeanDefinition 中的方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 public interface BeanDefinition extends AttributeAccessor , BeanMetadataElement { String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON; String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE; int ROLE_APPLICATION = 0 ; int ROLE_SUPPORT = 1 ; int ROLE_INFRASTRUCTURE = 2 ; void setParentName (@Nullable String parentName) ; @Nullable String getParentName () ; void setBeanClassName (@Nullable String beanClassName) ; @Nullable String getBeanClassName () ; void setScope (@Nullable String scope) ; @Nullable String getScope () ; void setLazyInit (boolean lazyInit) ; boolean isLazyInit () ; void setDependsOn (@Nullable String... dependsOn) ; @Nullable String[] getDependsOn(); void setAutowireCandidate (boolean autowireCandidate) ; boolean isAutowireCandidate () ; void setPrimary (boolean primary) ; boolean isPrimary () ; void setFactoryBeanName (@Nullable String factoryBeanName) ; @Nullable String getFactoryBeanName () ; void setFactoryMethodName (@Nullable String factoryMethodName) ; @Nullable String getFactoryMethodName () ; ConstructorArgumentValues getConstructorArgumentValues () ; default boolean hasConstructorArgumentValues () { return !getConstructorArgumentValues().isEmpty(); } MutablePropertyValues getPropertyValues () ; default boolean hasPropertyValues () { return !getPropertyValues().isEmpty(); } void setInitMethodName (@Nullable String initMethodName) ; @Nullable String getInitMethodName () ; void setDestroyMethodName (@Nullable String destroyMethodName) ; @Nullable String getDestroyMethodName () ; void setRole (int role) ; int getRole () ; void setDescription (@Nullable String description) ; @Nullable String getDescription () ; boolean isSingleton () ; boolean isPrototype () ; boolean isAbstract () ; @Nullable String getResourceDescription () ; @Nullable BeanDefinition getOriginatingBeanDefinition () ; }
方法名字类似我们 bean 标签的属性,setBeanClassName 对应 bean 标签中的 class 属性,所以当我们拿到 BeanDefinition 对象时,我们可以手动修改 bean 标签中所定义的属性值。 BeanDefinition 对象:我们在 XML 中定义的 bean 标签,Spring 解析 bean 标签成为一个 JavaBean, 这个JavaBean 就是 BeanDefinition。 注意:调用 BeanFactoryPostProcessor 方法时,这时候 bean 还没有实例化,此时 bean 刚被解析成 BeanDefinition 对象。