图文无关
Spring 框架的 IoC 容器(Inversion of Control,Ioc)是 Spring 框架中最基础、最重要的部分。Ioc 也被称为依赖注入(Dependency Injection,DI),是一种将组件依赖项的创建和管理外部化的技术。
图:Spring 架构图
1. Spring IoC 容器简介与 Beans
It is a process whereby objects define their dependencies (that is, the other objects they work with) only through constructor arguments, arguments to a factory method, or properties that are set on the object instance after it is constructed or returned from a factory method. The container then injects those dependencies when it creates the bean. This process is fundamentally the inverse (hence the name, Inversion of Control) of the bean itself controlling the instantiation or location of its dependencies by using direct construction of classes or a mechanism such as the Service Locator pattern. —— What is IoC ?
图:BeanFactory 局部结构
2. 容器概述
图:The Spring IoC container
最最最基础的示例:
package webj2ee;
public class HelloWorld { // Bean
public void sayHello(){
System.out.println("Hello World!");
}
}
<?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"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util
http://www.springframework.org/schema/util/spring-util.xsd ">
<bean id="helloWorld" class="webj2ee.HelloWorld"/>
</beans>
package webj2ee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Demo {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
HelloWorld helloWorld = context.getBean("helloWorld", HelloWorld.class);
helloWorld.sayHello();
}
}
3. Bean 概述
Spring IoC 容器管理着那些构成你应用的对象(Bean),这些 Bean 如何初始化、组装则是通过你提供给 IoC 容器的“配置元数据(XML、注解、Java、Groovy)”控制。不管是哪种形式的“配置元数据”,在 IoC 容器内部,都会转换为 BeanDefinition。
图:BeanDefinition 基本结构
3.1. 命名 Beans
示例:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="hello" name="hello1, hello2, hello3" class="webj2ee.Hello"/>
<alias name="hello" alias="hello4"/>
</beans>
package webj2ee;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Demo {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
Object o = context.getBean("hello");
Object o1 = context.getBean("hello1");
Object o2 = context.getBean("hello2");
Object o3 = context.getBean("hello3");
Object o4 = context.getBean("hello4");
System.out.println(o == o1);
System.out.println(o1 == o2);
System.out.println(o2 == o3);
System.out.println(o3 == o4);
String[] aliases = context.getAliases("hello");
System.out.println(StringUtils.join(aliases, ", "));
}
}
/**
* Utility method to take a string and convert it to normal Java variable
* name capitalization. This normally means converting the first
* character from upper case to lower case, but in the (unusual) special
* case when there is more than one character and both the first and
* second characters are upper case, we leave it alone.
* <p>
* Thus "FooBah" becomes "fooBah" and "X" becomes "x", but "URL" stays
* as "URL".
*
* @param name The string to be decapitalized.
* @return The decapitalized version of the string.
*/
public static String decapitalize(String name) {
if (name == null || name.length() == 0) {
return name;
}
if (name.length() > 1 && Character.isUpperCase(name.charAt(1)) &&
Character.isUpperCase(name.charAt(0))){
return name;
}
char chars[] = name.toCharArray();
chars[0] = Character.toLowerCase(chars[0]);
return new String(chars);
}
代码:java.beans 的命名规范代码;
3.2. 实例化 Beans
示例1:(构造函数)
package webj2ee;
public class HelloWorld {
public void sayHello(){
System.out.println("Hello World!");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="helloWorld" class="webj2ee.HelloWorld"/>
</beans>
package webj2ee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Demo {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
HelloWorld o = context.getBean("helloWorld", HelloWorld.class);
o.sayHello();
}
}
示例2:(静态工厂方法实例化Bean)
package webj2ee;
public class HelloWorld {
private static HelloWorld instance = new HelloWorld();
private HelloWorld(){}
public static HelloWorld getInstance(){
return instance;
}
public void sayHello(){
System.out.println("Hello World!");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="helloWorld" class="webj2ee.HelloWorld" factory-method="getInstance"/>
</beans>
package webj2ee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Demo {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
HelloWorld o = context.getBean("helloWorld", HelloWorld.class);
o.sayHello();
}
}
示例3:(实例工厂方法实例化Bean)
package webj2ee;
public class HelloWorld {
private static HelloWorld instance = new HelloWorld();
private HelloWorld(){
}
public HelloWorld getInstance(){
return instance;
}
public void sayHello(){
System.out.println("Hello World!");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="helloWorldGetter" class="webj2ee.HelloWorld"/>
<bean id="helloWorld" factory-bean="helloWorldGetter" factory-method="getInstance"/>
</beans>
package webj2ee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Demo {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
HelloWorld o = context.getBean("helloWorld", HelloWorld.class);
o.sayHello();
}
}
4. 依赖关系管理
4.1. 依赖注入
package webj2ee;
public class ExampleBean {
// Number of years to calculate the Ultimate Answer
private int years;
// The Answer to Life, the Universe, and Everything
private String ultimateAnswer;
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
@Override
public String toString() {
return "ExampleBean{" +
"years=" + years +
", ultimateAnswer='" + ultimateAnswer + '\'' +
'}';
}
}
示例1:通过 type 标记构造函数参数的顺序
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="exampleBean" class="webj2ee.ExampleBean">
<constructor-arg type="int" value="7500000"/>
<constructor-arg type="java.lang.String" value="42"/>
</bean>
</beans>
示例2:通过 index 标记构造函数参数的顺序
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="exampleBean" class="webj2ee.ExampleBean">
<constructor-arg index="0" value="7500000"/>
<constructor-arg index="1" value="42"/>
</bean>
</beans>
示例3:通过 name 标记构造函数参数的顺序
package webj2ee;
import java.beans.ConstructorProperties;
public class ExampleBean {
// Number of years to calculate the Ultimate Answer
private int years;
// The Answer to Life, the Universe, and Everything
private String ultimateAnswer;
@ConstructorProperties({"years", "ultimateAnswer"})
public ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
@Override
public String toString() {
return "ExampleBean{" +
"years=" + years +
", ultimateAnswer='" + ultimateAnswer + '\'' +
'}';
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="exampleBean" class="webj2ee.ExampleBean">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
</beans>
示例4:静态工厂方法——构造器注入
package webj2ee;
public class ExampleBean {
// Number of years to calculate the Ultimate Answer
private int years;
// The Answer to Life, the Universe, and Everything
private String ultimateAnswer;
private ExampleBean(int years, String ultimateAnswer) {
this.years = years;
this.ultimateAnswer = ultimateAnswer;
}
private static ExampleBean getInstance(int years, String ultimateAnswer) {
return new ExampleBean(years, ultimateAnswer);
}
@Override
public String toString() {
return "ExampleBean{" +
"years=" + years +
", ultimateAnswer='" + ultimateAnswer + '\'' +
'}';
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="exampleBean" class="webj2ee.ExampleBean" factory-method="getInstance">
<constructor-arg name="years" value="7500000"/>
<constructor-arg name="ultimateAnswer" value="42"/>
</bean>
</beans>
示例5:构造器注入——循环依赖
package webj2ee;
public class Abean {
public Abean(Bbean b){ }
}
package webj2ee;
public class Bbean {
public Bbean(Abean a){ }
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="abean" class="webj2ee.Abean">
<constructor-arg ref="bbean"/>
</bean>
<bean id="bbean" class="webj2ee.Bbean">
<constructor-arg ref="abean"/>
</bean>
</beans>
4.2. 依赖注入细节
示例1:通过 <property> 指定基本数据类型;
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close">
<property name="url" value="jdbc:mysql://localhost:3306/mydb" />
<property name="username" value="root" />
<property name="password" value="oracledba" />
<property name="initialSize" value="1" />
<property name="minIdle" value="1" />
<property name="maxActive" value="20" />
<property name="maxWait" value="60000" />
</bean>
</beans>
示例2:通过 p-namespace 简化 <property> 语法;
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"
init-method="init" destroy-method="close"
p:url="jdbc:mysql://localhost:3306/mydb"
p:username="root"
p:password="oracledba"
p:initialSize="1"
p:minIdle="1"
p:maxActive="20"
p:maxWait="6000">
</bean>
</beans>
示例3:引用 bean(java.util.Properties);
package webj2ee;
import java.util.Properties;
public class ExampleBean {
private Properties props;
public ExampleBean(Properties props){
this.props = props;
}
@Override
public String toString() {
return "ExampleBean{" +
"props=" + props +
'}';
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="exampleBean" class="webj2ee.ExampleBean">
<constructor-arg>
<!-- 通过 <props> 构造 java.util.Properties 对象 -->
<props>
<prop key="jdbc.driver.className">com.mysql.jdbc.Driver</prop>
<prop key="jdbc.url">jdbc:mysql://localhost:3306/mydb</prop>
</props>
</constructor-arg>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<!-- 通过 utils.properties 构造 java.util.Properties 对象 -->
<util:properties id="props">
<prop key="jdbc.driver.className">com.mysql.jdbc.Driver</prop>
<prop key="jdbc.url">jdbc:mysql://localhost:3306/mydb</prop>
</util:properties>
<!-- 完整版 -->
<bean id="exampleBean" class="webj2ee.ExampleBean">
<constructor-arg>
<ref bean="props"/>
</constructor-arg>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<util:properties id="props">
<prop key="jdbc.driver.className">com.mysql.jdbc.Driver</prop>
<prop key="jdbc.url">jdbc:mysql://localhost:3306/mydb</prop>
</util:properties>
<!-- 简化版 -->
<bean id="exampleBean" class="webj2ee.ExampleBean">
<constructor-arg ref="props"/>
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<util:properties id="props">
<prop key="jdbc.driver.className">com.mysql.jdbc.Driver</prop>
<prop key="jdbc.url">jdbc:mysql://localhost:3306/mydb</prop>
</util:properties>
<!-- 再简化 -->
<bean id="exampleBean" class="webj2ee.ExampleBean"
c:props-ref="props">
</bean>
</beans>
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="exampleBean" class="webj2ee.ExampleBean">
<constructor-arg>
<!-- InnerBean 形式注入 java.util.Properties 参数 -->
<util:properties>
<prop key="jdbc.driver.className">com.mysql.jdbc.Driver</prop>
<prop key="jdbc.url">jdbc:mysql://localhost:3306/mydb</prop>
</util:properties>
</constructor-arg>
</bean>
</beans>
示例4:引用父容器 bean(java.util.Properties);
parent.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<util:properties id="props">
<prop key="jdbc.driver.className">com.mysql.jdbc.Driver</prop>
<prop key="jdbc.url">jdbc:mysql://localhost:3306/mydb</prop>
</util:properties>
</beans>
child.xml:
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="exampleBean" class="webj2ee.ExampleBean">
<constructor-arg>
<ref parent="props"/>
</constructor-arg>
</bean>
</beans>
package webj2ee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
// parent context
ClassPathXmlApplicationContext parent = new ClassPathXmlApplicationContext("parent.xml");
// child context
ClassPathXmlApplicationContext child = new ClassPathXmlApplicationContext(new String[]{"child.xml"}, parent);
ExampleBean exampleBean = child.getBean("exampleBean", ExampleBean.class);
System.out.println(exampleBean);
}
}
4.3. depends-on、lazy-init
示例:
package webj2ee;
public class DependOnBeanA {
public DependOnBeanA() {
System.out.println("DependOnBeanA Init Success!");
}
}
package webj2ee;
public class DependOnBeanB {
public DependOnBeanB(){
System.out.println("DependOnBeanB Init Success!");
}
}
package webj2ee;
public class ExampleBean {
public ExampleBean(){
System.out.println("ExampleBean Init Success!");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="exampleBean" class="webj2ee.ExampleBean" depends-on="dependOnBeanA,dependOnBeanB"></bean>
<bean id="dependOnBeanA" class="webj2ee.DependOnBeanA"></bean>
<bean id="dependOnBeanB" class="webj2ee.DependOnBeanB"></bean>
</beans>
package webj2ee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
// parent context
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
ExampleBean exampleBean = context.getBean("exampleBean", ExampleBean.class);
System.out.println(exampleBean);
}
}
package webj2ee;
public class NotLazyBean {
public NotLazyBean(){
System.out.println("NotLazyBean Init Success!");
}
}
package webj2ee;
public class LazyBean {
public LazyBean(){
System.out.println("LazyBean Init Success!");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="lazyBean" class="webj2ee.LazyBean" lazy-init="true"></bean>
<bean id="notLazyBean" class="webj2ee.NotLazyBean"></bean>
</beans>
package webj2ee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
// parent context
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
System.out.println("After Container Init!");
System.out.println("Before get notLazyBean!");
NotLazyBean notLazyBean = context.getBean("notLazyBean", NotLazyBean.class);
System.out.println("After get notLazyBean!");
System.out.println("Before get lazyBean!");
LazyBean lazyBean = context.getBean("lazyBean", LazyBean.class);
System.out.println("After get lazyBean!");
}
}
4.4. Method Injection(Lookup Method)
反例:Singleton 依赖 Prototype,无法每次都得到新的 Prototype Bean;
package webj2ee;
public class PrototypeBean {
}
package webj2ee;
public class SingletonBean {
PrototypeBean prototypeBean;
public void setPrototypeBean(PrototypeBean prototypeBean) {
this.prototypeBean = prototypeBean;
}
public PrototypeBean getNewPrototypeBean(){
return prototypeBean;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="singletonBean" class="webj2ee.SingletonBean"
p:prototypeBean-ref="prototypeBean"/>
<bean id="prototypeBean" class="webj2ee.PrototypeBean" scope="prototype"></bean>
</beans>
package webj2ee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
SingletonBean singletonBean = context.getBean("singletonBean", SingletonBean.class);
System.out.println(singletonBean.getNewPrototypeBean() == singletonBean.getNewPrototypeBean());
}
}
正例1:通过 ApplicationContextAware 实现;
package webj2ee;
public class PrototypeBean {
}
package webj2ee;
import org.springframework.beans.BeansException;
import org.springframework.context.ApplicationContext;
import org.springframework.context.ApplicationContextAware;
public class SingletonBean implements ApplicationContextAware {
ApplicationContext applicationContext;
public PrototypeBean getNewPrototypeBean(){
return applicationContext.getBean("prototypeBean", PrototypeBean.class);
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="singletonBean" class="webj2ee.SingletonBean"/>
<bean id="prototypeBean" class="webj2ee.PrototypeBean" scope="prototype"></bean>
</beans>
package webj2ee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
SingletonBean singletonBean = context.getBean("singletonBean", SingletonBean.class);
System.out.println(singletonBean.getNewPrototypeBean() == singletonBean.getNewPrototypeBean());
}
}
正例2:通过 <lookup-method> 实现(CGLib)
package webj2ee;
public class PrototypeBean {
}
package webj2ee;
public abstract class SingletonBean {
public abstract PrototypeBean getNewPrototypeBean();
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="singletonBean" class="webj2ee.SingletonBean">
<lookup-method name="getNewPrototypeBean" bean="prototypeBean" ></lookup-method>
</bean>
<bean id="prototypeBean" class="webj2ee.PrototypeBean" scope="prototype"></bean>
</beans>
package webj2ee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
SingletonBean singletonBean = context.getBean("singletonBean", SingletonBean.class);
System.out.println(singletonBean.getNewPrototypeBean() == singletonBean.getNewPrototypeBean());
}
}
5. Bean 作用域
singleton:
prototype:
request、session、application:
6. Bean 生命周期控制、xxAware 接口
示例:
package webj2ee;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class ExampleBean implements InitializingBean, DisposableBean {
//////////////Initialization Callbacks//////////////
@PostConstruct
private void postConstruct(){
System.out.println("@PostConstruct");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet");
}
private void initMethod(){
System.out.println("init-method");
}
//////////////Destruction Callbacks//////////////
@PreDestroy
private void preDestory(){
System.out.println("@PreDestory");
}
@Override
public void destroy() throws Exception {
System.out.println("destory");
}
private void destoryMethod(){
System.out.println("destory-method");
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<context:annotation-config/>
<bean id="exampleBean" class="webj2ee.ExampleBean"
init-method="initMethod"
destroy-method="destoryMethod"></bean>
</beans>
package webj2ee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
ExampleBean exampleBean = context.getBean("exampleBean", ExampleBean.class);
System.out.println(">>>>");
context.close();
}
}
示例:
package webj2ee;
import org.springframework.beans.factory.BeanNameAware;
public class ExampleBean implements BeanNameAware {
@Override
public void setBeanName(String name) {
System.out.println("setBeanName triggered with: "+name);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<bean id="exampleBean" class="webj2ee.ExampleBean"></bean>
</beans>
package webj2ee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
ExampleBean exampleBean = context.getBean("exampleBean", ExampleBean.class);
}
}
7. 扩展 Spring 容器
示例:
package webj2ee;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.InitializingBean;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
public class ExampleBean implements InitializingBean, DisposableBean {
//////////////Initialization Callbacks//////////////
@PostConstruct
private void postConstruct(){
System.out.println("@PostConstruct");
}
@Override
public void afterPropertiesSet() throws Exception {
System.out.println("afterPropertiesSet");
}
private void initMethod(){
System.out.println("init-method");
}
//////////////Destruction Callbacks//////////////
@PreDestroy
private void preDestory(){
System.out.println("@PreDestory");
}
@Override
public void destroy() throws Exception {
System.out.println("destory");
}
private void destoryMethod(){
System.out.println("destory-method");
}
}
package webj2ee;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
public class InstantiationTracingBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean '" + beanName + "' before-created : " + bean.toString());
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("Bean '" + beanName + "' after-created : " + bean.toString());
return bean;
}
}
package webj2ee;
import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.core.annotation.Order;
@Order(2)
public class AnotherBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
System.out.println("AnotherBeanPostProcessor-Bean '" + beanName + "' before-created : " + bean.toString());
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
System.out.println("AnotherBeanPostProcessor-Bean '" + beanName + "' after-created : " + bean.toString());
return bean;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<context:annotation-config/>
<bean id="exampleBean" class="webj2ee.ExampleBean"
init-method="initMethod"
destroy-method="destoryMethod"></bean>
<bean class="webj2ee.InstantiationTracingBeanPostProcessor"/>
<bean class="webj2ee.AnotherBeanPostProcessor"/>
</beans>
package webj2ee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
ExampleBean exampleBean = context.getBean("exampleBean", ExampleBean.class);
context.close();
}
}
Customizing Configuration Metadata with a BeanFactoryPostProcessor:
示例1:(PropertyPlaceholderConfigurer )
package webj2ee;
public interface LanePromptDao {
LanePrompt getLanePromot(String promptId);
void saveLanePrompt(String promptId, LanePrompt lanePrompt);
}
package webj2ee;
public class SessionLanePromptDao implements LanePromptDao {
public SessionLanePromptDao() {
System.out.println("SessionLanePromptDao");
}
@Override
public LanePrompt getLanePromot(String promptId) {
return null;
}
@Override
public void saveLanePrompt(String promptId, LanePrompt lanePrompt) {
}
}
package webj2ee;
public class RedisLanePromptDao implements LanePromptDao {
public RedisLanePromptDao() {
System.out.println("RedisLanePromptDao");
}
@Override
public LanePrompt getLanePromot(String promptId) {
return null;
}
@Override
public void saveLanePrompt(String promptId, LanePrompt lanePrompt) {
}
}
package webj2ee;
public class LanePrompt {
private LanePromptDao dao;
public void setDao(LanePromptDao dao) {
this.dao = dao;
}
// ... business logic
}
// application.properties
dw.sef.SAVE_PROMPT_IN_REDIS=true
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<context:property-placeholder location="classpath:application.properties"/>
<bean id="lanePromptDao"
class="#{'${dw.sef.SAVE_PROMPT_IN_REDIS}'=='true' ?
'webj2ee.RedisLanePromptDao':
'webj2ee.SessionLanePromptDao'}"></bean>
<bean id="lanePrompt" class="webj2ee.LanePrompt"
p:dao-ref="lanePromptDao"/>
</beans>
package webj2ee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
LanePrompt lanePrompt = context.getBean("lanePrompt", LanePrompt.class);
context.close();
}
}
示例2:(PropertyOverrideConfigurer)
package webj2ee;
public class ExampleBean {
private String name;
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "ExampleBean{" +
"name='" + name + '\'' +
'}';
}
}
## override.properties
## beanName.property=value
exampleBean.name=xiaogang
<?xml version="1.0" encoding="UTF-8"?>
<beans ...>
<context:property-override location="classpath:override.properties"/>
<bean id="exampleBean" class="webj2ee.ExampleBean"
p:name="xiaohong"/>
</beans>
package webj2ee;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class Test {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("context.xml");
ExampleBean exampleBean = context.getBean("exampleBean", ExampleBean.class);
System.out.println(exampleBean);
context.close();
}
}
图:Spring 自带的 FactoryBean 实现类
package org.springframework.web.context.support;
import javax.servlet.ServletContext;
import org.springframework.beans.factory.FactoryBean;
import org.springframework.lang.Nullable;
import org.springframework.web.context.ServletContextAware;
public class ServletContextParameterFactoryBean implements FactoryBean<String>, ServletContextAware {
@Nullable
private String initParamName;
@Nullable
private String paramValue;
/**
* Set the name of the ServletContext init parameter to expose.
*/
public void setInitParamName(String initParamName) {
this.initParamName = initParamName;
}
@Override
public void setServletContext(ServletContext servletContext) {
if (this.initParamName == null) {
throw new IllegalArgumentException("initParamName is required");
}
this.paramValue = servletContext.getInitParameter(this.initParamName);
if (this.paramValue == null) {
throw new IllegalStateException("No ServletContext init parameter '" + this.initParamName + "' found");
}
}
@Override
@Nullable
public String getObject() {
return this.paramValue;
}
@Override
public Class<String> getObjectType() {
return String.class;
}
@Override
public boolean isSingleton() {
return true;
}
}
太长了....先写到这....下一篇继续....
参考:
Spring Framework Runtime: https://docs.spring.io/spring/docs/4.2.x/spring-framework-reference/html/overview.html The IoC Container: https://docs.spring.io/spring/docs/current/spring-framework-reference/core.html#spring-core Inversion of Control Containers and the Dependency Injection pattern: https://martinfowler.com/articles/injection.html 《Java Web 高级编程技术》 《Spring 入门经典》 《精通 Spring 4.x 企业应用开发实战》 《Spring5 高级编程》 《Spring实战(第3版)》