本想每个小知识一篇随笔,但是那样,看起来有些单薄,所以,就放在一片文章里了。而且,以后还会慢慢在最后不断的追加。
目录:
FactoryBean
BeanPostProcessor
1.FactoryBean
FactoryBean接口,它在Spring框架源码内部,被大量使用,如使用AOP创建bean的代理时,使用了ProxyFactoryBean;从JNDI中查找对象时,使用了JndiObjectFactoryBean。
它在框架外,很少使用。但是为了学习,也得研究研究,您说是不?
它怎么使用?首先看看构造。
public interface FactoryBean<T> { // 返回的是这个工厂管理的对象的实例
T getObject() throws Exception;
// 返回的是工厂创建的对象的类型
Class<?> getObjectType(); boolean isSingleton(); }
上个例子,看具体东西。
public class Tool { private int id;
public Tool(int id) {
this.id = id;
}
public int getId() {
return id;
} public void setId(int id) {
this.id = id;
}
}
public class ToolFactory implements FactoryBean<Tool> { private int factoryId;
private int toolId;
// 创建的是Tool的对象
@Override
public Tool getObject() throws Exception {
8 return new Tool(toolId);
9 } @Override
public Class<?> getObjectType() {
13 return Tool.class;
14 } @Override
public boolean isSingleton() {
return false;
} public int getFactoryId() {
return factoryId;
} public int getToolId() {
return toolId;
} public void setFactoryId(int factoryId) {
this.factoryId = factoryId;
} public void setToolId(int toolId) {
this.toolId = toolId;
} }
public class Test { public static void main(String[] args) {
@SuppressWarnings("resource")
ApplicationContext context = new ClassPathXmlApplicationContext("beaFactoryTest.xml");
Tool tool = (Tool) context.getBean("tool");
// 在名字前面加 & 表示要得到工厂类的bean
ToolFactory tool2 = (ToolFactory) context.getBean("&tool");
System.out.println("Tool Id is " + tool.getId());
System.out.println("ToolFactory Id is " + tool2.getFactoryId()); }
}
<bean id="tool" class="com.lee.demo.beanfactory.ToolFactory">
<property name="factoryId" value="9090"/>
<property name="toolId" value="108"/>
</bean>
最后执行结果:
Tool Id is 108
ToolFactory Id is 9090
2.BeanPostProcessor
它叫bean后处理器,也就是处理bean,它针对所有的bean,在初始化前后,对bean进行操作。主要内容我会在例子中描述。
例子:
public class HelloWorld {
private String message; public void setMessage(String message) {
this.message = message;
} public void getMessage() {
System.out.println("Your Message : " + message);
}
// 加上init方法和destory方法,是为了在后面验证他们和postProcessBeforeInitialization postProcessAfterInitialization 执行的先后顺序
public void init() {
System.out.println("Bean is going through init.");
} public void destroy() {
System.out.println("Bean will destroy now.");
}
}
public class InitHelloWorld implements BeanPostProcessor {
// BeanPostProcessor 接口中主要是下面两个方法 初始化前的后处理 初始化后的后处理
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException { System.out.println("BeforeInitialization : " + beanName);
return bean; // you can return any other object as well
} @Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException { System.out.println("AfterInitialization : " + beanName);
return bean; // you can return any other object as well
} }
Test.java
public class Test { public static void main(String[] args) {
@SuppressWarnings("resource")
AbstractApplicationContext context = new ClassPathXmlApplicationContext("beaFactoryTest.xml");
HelloWorld obj = (HelloWorld) context.getBean("helloWorld");
obj.getMessage();
// 注册钩子方法
context.registerShutdownHook();
}
}
查看源码:
@Override
// 在JVM运行期间,注册一个钩子关闭方法,关闭掉这个context。实际的关闭程序的操作,被代理给doClose方法。
public void registerShutdownHook() {
if (this.shutdownHook == null) {
// No shutdown hook registered yet.
this.shutdownHook = new Thread() {
@Override
public void run() {
doClose();
}
};
Runtime.getRuntime().addShutdownHook(this.shutdownHook);
}
}
xml文件
<bean id = "helloWorld" class = "com.lee.demo.beanfactory.HelloWorld"
init-method = "init" destroy-method = "destroy">
<property name = "message" value = "Hello World!"/>
</bean> <bean class = "com.lee.demo.beanfactory.InitHelloWorld" />
执行结果:
BeforeInitialization : helloWorld
Bean is going through init.
AfterInitialization : helloWorld
Your Message : Hello World!
[org.springframework.context.support.ClassPathXmlApplicationContext] - Closing org.springframework.context.support.ClassPathXmlApplicationContext@6ae40994: startup date [Thu May 17 23:31:53 JST 2018]; root of context hierarchy
Bean will destroy now.
在这里大致说一下Spring的实例化过程:
实例化Bean对象→设置对象属性→检查Aware相关接口并设置相关依赖→BeanPostProcessor前置处理→检查是否是InitializingBean以决定是否调用afterPropertiesSet方法→
检查是否配置有自定义的init-method方法→BeanPostProcessor后置处理→是否实现DisposableBean接口→是否配置有自定义的destroy方法
3.Aware接口
它是干什么用的呢?作用就是通过上下文(Context)可以获得当前环境。看看它的接口:
我们拿BeanNameAware来举个例子。
public class User implements GetNameAware { private String id;
private String name;
private String address;
6 @Override
7 public void setBeanName(String name) {
8 this.id = name;
9 }
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getAddress() {
return address;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAddress(String address) {
this.address = address;
} }
public class User2 { private String id;
private String name;
private String address;
public String getId() {
return id;
}
public String getName() {
return name;
}
public String getAddress() {
return address;
}
public void setId(String id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setAddress(String address) {
this.address = address;
} }
public interface GetNameAware extends BeanNameAware { }
public class Test {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("beaFactoryTest.xml");
User user = (User) ctx.getBean("user1");
User2 user2 = (User2) ctx.getBean("user2");
System.out.println("user id " + user.getId() + " user name " + user.getName() + " user address " + user.getAddress());
System.out.println("========================================");
System.out.println("user2 id " + user2.getId() + " user2 name " + user2.getName() + " user2 address " + user2.getAddress());
}
}
<bean id="user1" class="com.lee.demo.aware.User">
<property name="name" value="lee"/>
<property name="address" value="China"/>
</bean> <bean id="user2" class="com.lee.demo.aware.User2">
<property name="name" value="lin"/>
<property name="address" value="Tokyo"/>
</bean>
执行结果(user id 因为继承了GetNameAware接口,对BeanName进行了设置):
user id user1 user name lee user address China
========================================
user2 id null user2 name lin user2 address Tokyo