目录
前言

今天实现Bean后处理器也就是上图中右侧的部分。
Bean后处理器的作用
Bean后处理器的作用在Spring中是对Bean对象做功能增强的,Bean后处理器中有两个方法,暂时把他们叫为前方法与后方法。
- 前方法是在依赖注入结束之后执行,主要作用是对bean对象属性赋值。
- 然后执行bean对象的初始化方法。
- 其次再执行后方法。主要作用是对bean对象的方法增强。
自定义注解@MyPostConstruct
在Spring中,注解@PostConstruct用于初始化方法上。执行时机为依赖注入完成后,被标注的方法只会被执行一次。
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyPostConstruct {
}
自定义BeanPostProcessor后处理器接口
在Spring框架中,也可以自己自定义Bean后处理器添加到Spring启动流程中。只需要实现Spring框架中的BeanPostProcessor接口即可。
现在我们自定义BeanPostProcessor接口,来模仿Spring的实现方式。
/**
* 实现该接口的被当作Bean后处理器
*/
public interface MyBeanPostProcessor {
default Object postProcessBeforeInitialization(Object bean, String beanName) {
return bean;
}
default Object postProcessAfterInitialization(Object bean, String beanName){
return bean;
}
}
自定义Bean后处理器
接下来创建出一个类来实现Bean后处理器接口
@MyComponent
public class MyBeanPostProcess implements MyBeanPostProcessor{
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("执行Bean后处理器前方法:"+beanName);
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("执行Bean后处理器后方法:"+beanName);
return bean;
}
}
修改ApplicationContext类
首先我们要清楚,Bean后处理器可以有多个并且具有执行顺序的,并且执行时机为Bean自动装配之后,也就是在实例化BeanDefinitionMap之后且实例化SingletonObjects之前执行。从Bean后处理器执行时机我们知道Bean后处理器是不会被加载到单例池的。那么我们定义一个List列表来存储Bean后处理对象。
//用来存储Bean后处理器对象
private List<MyBeanPostProcessor> beanPostProcesses;
//初始化代码块
{
beanPostProcesses = new ArrayList<>();
}
Bean后处理器是在加入单例池之前执行,因此添加一个新的initBeanPostProcess()方法
private void initBeanPostProcess() {
Set<Map.Entry<String, BeanDefinition>> entries = this.beanDefinitionMap.entrySet();
for (Map.Entry<String, BeanDefinition> entry : entries) {
if (MyBeanPostProcessor.class.isAssignableFrom(entry.getValue().getClazz())){
try {
String beanName = entry.getKey();
Object o = entry.getValue().getClazz().newInstance();
beanPostProcessors.add((MyBeanPostProcessor) o);
singletonObjects.put(beanName,o);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
接下来需要修改加载bean对象到单例池中方法,在此之前需要先执行bean后处理器方法,但需要注意的是,我们需要对bean处理器本身过滤
private void createBean(Map.Entry<String, BeanDefinition> entry) {
//获取到类
Object o = null;
String beanName = entry.getKey();
if (cacheSingleton.containsKey(beanName)) {
o = cacheSingleton.get(beanName);
} else {
Class<?> clazz = entry.getValue().getClazz();
try {
o = clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
//获取该类中的字段
Field[] declaredFields = o.getClass().getDeclaredFields();
for (Field declaredField : declaredFields) {
//判断字段上是否存在@MyResource注解
if (declaredField.isAnnotationPresent(MyResource.class)) {
MyResource annotation = declaredField.getAnnotation(MyResource.class);
//需要被注入的名称
String setBeanName = annotation.value();
if ("".equals(setBeanName)) {
//如果MyResource没有指定,那么以字段名为注入名
setBeanName = declaredField.getName();
}
if (!beanDefinitionMap.containsKey(setBeanName)) {
throw new RuntimeException("不存在该bean名称:" + setBeanName);
}
//开放权限
declaredField.setAccessible(true);
BeanDefinition beanDefinition = beanDefinitionMap.get(setBeanName);
try {
if (beanDefinition.getType().equals("Singleton")) {
//如果是单例bean
if (!cacheSingleton.containsKey(setBeanName)) {
//如果缓存单例池不存在,那么去单例池寻找
if (singletonObjects.containsKey(setBeanName)) {
//单例池存在的情况
Object o1 = singletonObjects.get(setBeanName);
declaredField.set(o, o1);
} else {
//单例池中也不存在
Object o1 = beanDefinition.getClazz().newInstance();
//存放在缓存单例池中
cacheSingleton.put(setBeanName, o1);
declaredField.set(o, o1);
}
} else {
//如果已经创建过了,但未完成创建
Object o1 = cacheSingleton.get(setBeanName);
declaredField.set(o, o1);
}
} else {
Object o1 = beanDefinition.getClazz().newInstance();
declaredField.set(o, o1);
}
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
}
//到这里执行结束,清除缓存单例池信息
//去执行Bean后处理器后再添加到单例池
executeBeanPostBefore(o, beanName);
executeBeanInit(o);
executeBeanPostAfter(o, beanName);
cacheSingleton.remove(beanName);
if (entry.getValue().getType().equals("Singleton")) {
singletonObjects.put(beanName, o);
}
}
首先将未经过Bean后处理加工过的单例bean加载到单例池中(注:Spring中不会这样做,Spring中有三级缓存分步加载到单例池)如果遍历到Bean后处理器对象,那么就将其加入List列表。
接下来我们要调用执行Bean后处理器的方法,以及bean对象的初始化方法,这个三个方法实现如下
/**
* Bean后处理器前方法执行
* @param o 需要被被处理的bean
* @param beanName 该bean的名称
*/
private void executeBeanPostAfter(Object o, String beanName) {
for (MyBeanPostProcessor beanPostProcessor : beanPostProcessors) {
if (o instanceof MyBeanPostProcessor) {
break;
}
beanPostProcessor.postProcessAfterInitialization(o, beanName);
}
}
/**
* Bean后处理器后方法执行
*
* @param o 需要被被处理的bean
* @param beanName 该bean的名称
*/
private void executeBeanPostBefore(Object o, String beanName) {
for (MyBeanPostProcessor beanPostProcessor : beanPostProcessors) {
if (o instanceof MyBeanPostProcessor) {
break;
}
beanPostProcessor.postProcessBeforeInitialization(o, beanName);
}
}
/**
* Bean初始化
* 需要编写一个判断Bean是否存在初始化方法
*/
private void executeBeanInit(Object o) {
for (Method method : o.getClass().getDeclaredMethods()) {
//获取method方法,并判断是否存在注解
if (method.isAnnotationPresent(MyPostConstruct.class)) {
try {
//即使是private修饰的方法也可以执行
method.setAccessible(true);
method.invoke(o);
} catch (IllegalAccessException | InvocationTargetException e) {
System.out.println("bean初始化失败");
e.printStackTrace();
}
}
}
}
在依赖注入后依次调用这三个方法,对加工后的Bean放入单例池。
测试
@MyComponent
public class People {
private String name;
@MyPostConstruct
public void init(){
this.name = "张三";
System.out.println("people名字叫"+name);
}
}

可以看到,每创建一个Bean就执行一次Bean 后处理器,同时也能执行bean的初始化方法。
完整代码
这次的改动比较大,修改过后的ApplicationContext的完整代码如下
public class SpringApplication3 {
//配置类属性
private Class<?> configClass;
//单例池
private ConcurrentHashMap<String, Object> singletonObjects;
//BeanDefinitionMap
private Map<String, BeanDefinition> beanDefinitionMap;
private Map<String, Object> cacheSingleton;
private List<MyBeanPostProcessor> beanPostProcessors;
//每创建一个容器都会有各自的单例池
{
singletonObjects = new ConcurrentHashMap<>(256);
beanDefinitionMap = new ConcurrentHashMap<>(256);
cacheSingleton = new ConcurrentHashMap<>(256);
beanPostProcessors = new ArrayList<>();
}
public SpringApplication3(Class<?> configClass) throws Exception {
this.configClass = configClass;
this.init();
this.initBeanPostProcess();
this.initSingletonObjects();
}
private void init() throws Exception {
//判断该类是否是配置类
MyConfiguration configuration = configClass.getAnnotation(MyConfiguration.class);
if (configuration == null) {
//说明不是配置类
throw new RuntimeException("该类不是配置类,目前只支持传入配置类");
}
//如果是配置类,那么获取需要扫描的类路径
MyComponentScan scan = configClass.getAnnotation(MyComponentScan.class);
if (scan == null) {
throw new RuntimeException("不存在扫描注解");
}
String[] paths = scan.value();
//遍历需要扫描的路径
for (String path : paths) {
path = URLDecoder.decode(path, "UTF-8");
//path这里还有作用,因此不建议将path接收replace的结果
// com/zmt
String newPath = path.replace(".", "/");
//获取根路径,并去除最前面的/
String classPath = configClass.getResource("/").getPath().substring(1);
classPath = URLDecoder.decode(classPath, "UTF-8");
System.out.println("classPath:" + classPath);
//获取被扫描包的绝对路径
String absolutePath = configClass.getResource("/" + newPath).getPath();
absolutePath = URLDecoder.decode(absolutePath, "UTF-8");
System.out.println(absolutePath);
//遍历绝对路径的子包,寻找.class结尾的文件
File rootFile = new File(absolutePath);
if (rootFile.isFile()) {
throw new RuntimeException("不支持扫描具体类");
}
//说明指定路径是一个文件夹
//获取所有的类名称
List<String> listClass = dirFile(rootFile);
for (String absoluteClassPath : listClass) {
//完整类名,通过Class.forName()创建出该类
String fullClassName = absoluteClassPath.replace(classPath, "").replace("/", ".");
//加载出该类
ClassLoader classLoader = configClass.getClassLoader();
Class<?> aClass = classLoader.loadClass(fullClassName);
MyComponent myComponent = aClass.getAnnotation(MyComponent.class);
if (myComponent == null) {
//该类不应该被加载
continue;
}
//获取Bean名称
String beanName = getBeanName(fullClassName, aClass, myComponent);
//判断是否添加了@MyScope注解,通知判断该注解的值
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setType("Singleton");
if (aClass.isAnnotationPresent(MyScope.class)) {
String value = aClass.getAnnotation(MyScope.class).value();
if (!"Singleton".equals(value) && "Prototype".equals(value)) {
//说明是不是非单例的对象
beanDefinition.setType("Prototype");
}
}
beanDefinition.setClazz(aClass);
beanDefinitionMap.put(beanName, beanDefinition);
}
}
}
/**
* 初始化Bean后处理器
*/
private void initBeanPostProcess() {
Set<Map.Entry<String, BeanDefinition>> entries = this.beanDefinitionMap.entrySet();
for (Map.Entry<String, BeanDefinition> entry : entries) {
if (MyBeanPostProcessor.class.isAssignableFrom(entry.getValue().getClazz())) {
try {
String beanName = entry.getKey();
Object o = entry.getValue().getClazz().newInstance();
beanPostProcessors.add((MyBeanPostProcessor) o);
singletonObjects.put(beanName, o);
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
private void initSingletonObjects() {
//从BeanDefinitionMap当中获取信息并加载单例对象到单例池中
Set<Map.Entry<String, BeanDefinition>> entries = this.beanDefinitionMap.entrySet();
for (Map.Entry<String, BeanDefinition> entry : entries) {
createBean(entry);
}
}
/**
* 实现依赖注入
*
* @param entry
*/
private void createBean(Map.Entry<String, BeanDefinition> entry) {
//获取到类
Object o = null;
String beanName = entry.getKey();
if (cacheSingleton.containsKey(beanName)) {
o = cacheSingleton.get(beanName);
} else {
Class<?> clazz = entry.getValue().getClazz();
try {
o = clazz.newInstance();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
//获取该类中的字段
Field[] declaredFields = o.getClass().getDeclaredFields();
for (Field declaredField : declaredFields) {
//判断字段上是否存在@MyResource注解
if (declaredField.isAnnotationPresent(MyResource.class)) {
MyResource annotation = declaredField.getAnnotation(MyResource.class);
//需要被注入的名称
String setBeanName = annotation.value();
if ("".equals(setBeanName)) {
//如果MyResource没有指定,那么以字段名为注入名
setBeanName = declaredField.getName();
}
if (!beanDefinitionMap.containsKey(setBeanName)) {
throw new RuntimeException("不存在该bean名称:" + setBeanName);
}
//开放权限
declaredField.setAccessible(true);
BeanDefinition beanDefinition = beanDefinitionMap.get(setBeanName);
try {
if (beanDefinition.getType().equals("Singleton")) {
//如果是单例bean
if (!cacheSingleton.containsKey(setBeanName)) {
//如果缓存单例池不存在,那么去单例池寻找
if (singletonObjects.containsKey(setBeanName)) {
//单例池存在的情况
Object o1 = singletonObjects.get(setBeanName);
declaredField.set(o, o1);
} else {
//单例池中也不存在
Object o1 = beanDefinition.getClazz().newInstance();
//存放在缓存单例池中
cacheSingleton.put(setBeanName, o1);
declaredField.set(o, o1);
}
} else {
//如果已经创建过了,但未完成创建
Object o1 = cacheSingleton.get(setBeanName);
declaredField.set(o, o1);
}
} else {
Object o1 = beanDefinition.getClazz().newInstance();
declaredField.set(o, o1);
}
} catch (IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
}
//到这里执行结束,清除缓存单例池信息
//去执行Bean后处理器后再添加到单例池
executeBeanPostBefore(o, beanName);
executeBeanInit(o);
executeBeanPostAfter(o, beanName);
cacheSingleton.remove(beanName);
if (entry.getValue().getType().equals("Singleton")) {
singletonObjects.put(beanName, o);
}
}
private void executeBeanPostAfter(Object o, String beanName) {
for (MyBeanPostProcessor beanPostProcessor : beanPostProcessors) {
if (o instanceof MyBeanPostProcessor) {
break;
}
beanPostProcessor.postProcessAfterInitialization(o, beanName);
}
}
private void executeBeanInit(Object o) {
for (Method method : o.getClass().getDeclaredMethods()) {
//获取method方法,并判断是否存在注解
if (method.isAnnotationPresent(MyPostConstruct.class)) {
try {
//即使是private修饰的方法也可以执行
method.setAccessible(true);
method.invoke(o);
} catch (IllegalAccessException | InvocationTargetException e) {
System.out.println("bean初始化失败");
e.printStackTrace();
}
}
}
}
private void executeBeanPostBefore(Object o, String beanName) {
for (MyBeanPostProcessor beanPostProcessor : beanPostProcessors) {
if (o instanceof MyBeanPostProcessor) {
break;
}
beanPostProcessor.postProcessBeforeInitialization(o, beanName);
}
}
private String getBeanName(String fullClassName, Class<?> aClass, MyComponent myComponent) {
//如果注解中没有没有给定值,那么采用类名首字母小写的方式
String beanName = myComponent.value();
if ("".equals(beanName)) {
System.out.println(aClass.getName() + "没有指定bean名称");
String className = fullClassName.substring(fullClassName.lastIndexOf(".") + 1);
beanName = className.substring(0, 1).toLowerCase() + className.substring(1);
}
return beanName;
}
/**
* 遍历文件夹,获取所有类绝对路径集合
*
* @param rootFile
* @return
*/
private List<String> dirFile(File rootFile) {
List<String> fileList = new ArrayList<>();
if (rootFile.isDirectory()) {
File[] files = rootFile.listFiles();
for (File file : files) {
fileList.addAll(dirFile(file));
}
} else {
//走到这说明已经不是文件夹了
String filePath = rootFile.getPath();
if (filePath.endsWith(".class")) {
//类的绝对路径
String classPath = filePath.replace("\\", "/").replace(".class", "");
fileList.add(classPath);
}
}
return fileList;
}
public Object getBean(String beanName) {
Object o = this.singletonObjects.get(beanName);
if (o == null) {
throw new RuntimeException("不存在bean为:" + beanName);
}
return o;
}
}
本文介绍了如何在Spring框架中自定义Bean后处理器,使用自定义注解@MyPostConstruct,并详细解释了其在Bean对象生命周期中的作用,包括前方法和后方法,以及如何在ApplicationContext中集成和执行这些处理器。
1050





