文章目录
目前进度
Spring源码学习,进行简单模拟实现,一步步搭建。
当前完成:
ComponentScan
扫描指定路径包(不递归,且认为都是class文件,直接类加载方式)Scope
区分单例与多例Bean(单例Bean创建放入单例池)Autowired
依赖注入(不考虑循环依赖)BeanDefinition
只考虑了type
,scope
,lazy
(未实现)InitializingBean
IOC注入完成后执行afterPropertiesSet
BeanPostProcessor
初始化前后执行前置后置方法Aware
普通对象依赖注入后,初始化前,注入Spring
属性
目的
- 通过手写模拟,了解Spring的底层源码启动过程
- 通过手写模拟,了解BeanDefinition、BeanPostProcessor的概念
- 通过手写模拟,了解Spring解析配置类等底层源码工作流程
- 通过手写模拟,了解依赖注入,Aware回调等底层源码工作流程
- 通过手写模拟,了解Spring AOP的底层源码工作流程
搭建基础
- 创建一个
ApplicationContext
对象, 通过该对象读取一个Config
配置类信息。 - 通过
ApplicationContext
对象的getBean()
方法获取bean
对象, 并调用bean
对象方法。
KunApplicationContext
package com.spring;
/**
* @author guokun
* @date 2022/9/5 17:03
*/
public class KunApplicationContext {
private Class<?> configClass;
public KunApplicationContext(Class<?> configClass) {
this.configClass = configClass;
// To Do: 根据Config中指定的扫描路径扫描
}
public Object getBean(String beanName) {
return null;
}
}
测试类 Test
import com.kun.config.KunAppConfig;
import com.kun.service.KunService;
import com.spring.KunApplicationContext;
/**
* @author guokun
* @date 2022/9/5 17:05
*/
public class Test {
public static void main(String[] args) {
KunApplicationContext kunApplicationContext = new KunApplicationContext(KunAppConfig.class);
KunService kunService = (KunService) kunApplicationContext.getBean("kunService");
kunService.test();
}
}
ComponentScan
注解
package com.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author guokun
* @date 2022/9/5 17:17
*
* 运行时生效
* 类注解
* 扫描指定路径下得所有Component
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
String value() default "";
}
Component
注解
package com.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author guokun
* @date 2022/9/5 17:17
* 运行时生效
* 类注解
* 声明为需要创建的bean类,可以指定bean的名字
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
String value() default "";
}
KunService
服务类(Bean类)
package com.kun.service;
import com.spring.annotation.Component;
/**
* @author guokun
* @date 2022/9/5 17:15
*/
@Component("kunService")
public class KunService {
public void test() {
System.out.println("kunService test()");
}
}
实现包扫描
- 包扫描流程在前面基础框架可以知道应该在
ApplicationContext
对象创建时进行。(构造方法中调用)
public KunApplicationContext(Class<?> configClass) {
this.configClass = configClass;
componentScan();
}
private void componentScan(Class<?> configClass) {
}
}
- 首先需要判断对应的
Config
类中有没有ComponentScan
注解,才可以扫描指定的包
- 通过
isAnnotationPresent()
查看某个类是否含有某个注解- 通过
getAnnotation()
获取某个类的某个注解对象
private void componentScan() {
// 扫描包
if (configClass.isAnnotationPresent(ComponentScan.class)) {
ComponentScan componentScanAnnotation = configClass.getAnnotation(ComponentScan.class);
// 获取包路径 xx.xx.xx
String packagePath = componentScanAnnotation.value();
}
}
- 由于
JVM
是读取class
文件的,因此我们可以通过AppClassLoader
来获取指定包的相对文件路径(注意需要将包格式转换为文件路径格式)
private void componentScan() {
// 扫描包
if (configClass.isAnnotationPresent(ComponentScan.class)) {
ComponentScan componentScanAnnotation = configClass.getAnnotation(ComponentScan.class);
// 获取包路径 xx.xx.xx
String packagePath = componentScanAnnotation.value();
// 格式转换为 xx/xx/xx (因为我们要去加载的是class文件,通过文件系统去读取)
String filePath = packagePath.replace(".", "/");
// 获取类加载器(AppClassLoader)
ClassLoader classLoader = KunApplicationContext.class.getClassLoader();
// 使用AppClassLoader去获取指定包下的class文件夹路径
URL targetClassUrl = classLoader.getResource(filePath);
}
}
- 打开对应目录文件,并加载所有的
Class
,然后检查是否含有Component
注解
- 在Spring中使用ASM技术扫描,无需加载类,此处直接通过将所有类加载后判断是否有
Component
注解实现- 此处先只考虑当前包,不考虑子包
- 假设该目录下所有文件都是
class
文件,不去考虑其他类型文件
// 获取对应的文件目录
assert targetClassUrl != null;
File targetClassDir = new File(targetClassUrl.getFile());
// 检查是否是一个文件目录
if (targetClassDir.isDirectory()) {
// 获取所有子文件 (先只考虑当前包,不考虑子包,假设子文件都是class文件)
File[] classFiles = targetClassDir.listFiles();
assert classFiles != null;
List<Class<?>> classList = new ArrayList<>(classFiles.length);
for (File classFile : classFiles) {
// 获取class文件名称 xx.class
String classFileName = classFile.getName();
// 获取类名(去除.class)
String className = classFileName.substring(0, classFileName.length() - 6);
String classFullName = packagePath + "." + className;
try {
// 使用类加载器(AppClassLoader)加载类
Class<?> loadClass = classLoader.loadClass(classFullName);
// 检查是否含有Component注解
if (loadClass.isAnnotationPresent(Component.class)) {
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
- 获取
beanName
,如果Component
注解上为空串则使用类名的小驼峰命名作为beanName
// 检查是否含有Component注解
if (loadClass.isAnnotationPresent(Component.class)) {
// 获取beanName
Component componentAnnotation = loadClass.getAnnotation(Component.class);
String beanName = componentAnnotation.value();
// 如果beanName没有设置则使用类名的小驼峰命名作为beanName
if ("".equals(beanName)) {
beanName = Introspector.decapitalize(loadClass.getSimpleName());
}
}
- 创建注解
Scope
来区分单例与多例bean
package com.spring.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @author guokun
* @date 2022/9/5 19:44
* 运行时类注解
* value: singleton(单例) prototype(多例)
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
String value() default "singleton";
}
区分是否单例
// 检查是否含有Component注解
if (loadClass.isAnnotationPresent(Component.class)) {
// 获取beanName
Component componentAnnotation = loadClass.getAnnotation(Component.class);
String beanName = componentAnnotation.value();
// 如果beanName没有设置则使用类名的小驼峰命名作为beanName
if ("".equals(beanName)) {
beanName = Introspector.decapitalize(loadClass.getSimpleName());
}
// 查看是否是单例bean
if (loadClass.isAnnotationPresent(Scope.class)
&& "prototype".equals(loadClass.getAnnotation(Scope.class).value())) {
// 多例bean
} else {
// 单例bean
}
}
创建BeanDefinition
BeanDefinition
类
package com.spring;
/**
* @author guokun
* @date 2022/9/5 20:06
*/
public class BeanDefinition {
private Class<?> type;
private String scope;
private boolean isLazy;
public Class<?> getType() {
return type;
}
public void setType(Class<?> type) {
this.type = type;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
public boolean isLazy() {
return isLazy;
}
public void setLazy(boolean lazy) {
isLazy = lazy;
}
}
- 在
ApplicationContext
中使用一个HashMap
来存储BeanDefinition
private HashMap<String, BeanDefinition> beanDefinitionMap = new HashMap<>();
- 将扫描的
Bean
的信息封装成BeanDefinition
并放入map集合中
private void componentScan() {
// 扫描包
if (configClass.isAnnotationPresent(ComponentScan.class)) {
ComponentScan componentScanAnnotation = configClass.getAnnotation(ComponentScan.class);
// 获取包路径 xx.xx.xx
String packagePath = componentScanAnnotation.value();
// 格式转换为 xx/xx/xx (因为我们要去加载的是class文件,通过文件系统去读取)
String filePath = packagePath.replace(".", "/");
// 获取类加载器(AppClassLoader)
ClassLoader classLoader = KunApplicationContext.class.getClassLoader();
// 使用AppClassLoader去获取指定包下的class文件夹路径
URL targetClassUrl = classLoader.getResource(filePath);
// 获取对应的文件目录
assert targetClassUrl != null;
File targetClassDir = new File(targetClassUrl.getFile());
// 检查是否是一个文件目录
if (targetClassDir.isDirectory()) {
// 获取所有子文件 (先只考虑当前包,不考虑子包,假设子文件都是class文件)
File[] classFiles = targetClassDir.listFiles();
assert classFiles != null;
List<Class<?>> classList = new ArrayList<>(classFiles.length);
for (File classFile : classFiles) {
// 获取class文件名称 xx.class
String classFileName = classFile.getName();
// 获取类名(去除.class)
String className = classFileName.substring(0, classFileName.length() - 6);
String classFullName = packagePath + "." + className;
try {
// 使用类加载器(AppClassLoader)加载类
Class<?> loadClass = classLoader.loadClass(classFullName);
// 检查是否含有Component注解
if (loadClass.isAnnotationPresent(Component.class)) {
// 创建BeanDefinition
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setType(loadClass);
// 获取beanName
Component componentAnnotation = loadClass.getAnnotation(Component.class);
String beanName = componentAnnotation.value();
// 如果beanName没有设置则使用类名的小驼峰命名作为beanName
if ("".equals(beanName)) {
beanName = Introspector.decapitalize(loadClass.getSimpleName());
}
// 查看是否是单例bean
if (loadClass.isAnnotationPresent(Scope.class)
&& "prototype".equals(loadClass.getAnnotation(Scope.class).value())) {
// 多例bean
beanDefinition.setScope("prototype");
} else {
// 单例bean
beanDefinition.setScope("singleton");
}
// 存储BeanDefinition到map中
beanDefinitionMap.put(beanName, beanDefinition);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
getBean()
判断是否存在对应的BeanDefinition
public Object getBean(String beanName) {
// 如果BeanDefinitionMap中没有对应的则说明该bean不在扫描的范围内
if (!beanDefinitionMap.containsKey(beanName)) {
return null;
}
// 有对应的BeanDefinition
Object bean = null;
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if ("prototype".equals(beanDefinition.getScope())) {
// 多例
} else {
// 单例
}
return bean;
}
创建Bean
- 创建
Bean
的方法createBean()
,简单通过反射使用无参构造器创建一个实例。
private Object createBean(String beanName, BeanDefinition beanDefinition) {
Class<?> cla = beanDefinition.getType();
Object bean = null;
try {
bean = cla.getDeclaredConstructor().newInstance();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return bean;
}
2 getBean()
中原型(多例)Bean
返回新对象
public Object getBean(String beanName) {
// 如果BeanDefinitionMap中没有对应的则说明该bean不在扫描的范围内
if (!beanDefinitionMap.containsKey(beanName)) {
return null;
}
// 有对应的BeanDefinition
Object bean = null;
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if ("prototype".equals(beanDefinition.getScope())) {
// 多例
bean = createBean(beanName, beanDefinition);
} else {
// 单例
}
return bean;
}
- 扫描后创建单例
Bean
,使用一个单例Bean
的HashMap
进行存储singletonObjects
扫描后创建单例
private void createSingletonBeans() {
for (Map.Entry<String, BeanDefinition> beanDefinitionEntry : beanDefinitionMap.entrySet()) {
String beanName = beanDefinitionEntry.getKey();
BeanDefinition beanDefinition = beanDefinitionEntry.getValue();
// 检查是否是singleton
if ("singleton".equals(beanDefinition.getScope())) {
Class<?> cla = beanDefinition.getType();
Object bean = createBean(beanName, beanDefinition);
singletonObjects.put(beanName, bean);
}
}
}
构造方法中调用:
public KunApplicationContext(Class<?> configClass) {
this.configClass = configClass;
componentScan();
createSingletonBeans();
}
getBean()
返回单例池中的单例对象public Object getBean(String beanName) { // 如果BeanDefinitionMap中没有对应的则说明该bean不在扫描的范围内 if (!beanDefinitionMap.containsKey(beanName)) { return null; } // 有对应的BeanDefinition Object bean = null; BeanDefinition beanDefinition = beanDefinitionMap.get(beanName); if ("prototype".equals(beanDefinition.getScope())) { // 多例 bean = createBean(beanName, beanDefinition); } else { // 单例 bean = singletonObjects.get(beanName); } return bean; }
测试容器单例与多例bean
创新新的服务类:
GuoService
package com.kun.service; import com.spring.annotation.Component; import com.spring.annotation.Scope; /** * @author guokun * @date 2022/9/5 17:15 */ @Component("guoService") @Scope("prototype") public class GuoService { public void test() { System.out.println("guoService test()"); } }
修改测试类:
Test
import com.kun.config.KunAppConfig; import com.kun.service.GuoService; import com.kun.service.KunService; import com.spring.KunApplicationContext; /** * @author guokun * @date 2022/9/5 17:05 */ public class Test { public static void main(String[] args) { KunApplicationContext kunApplicationContext = new KunApplicationContext(KunAppConfig.class); KunService kunService = (KunService) kunApplicationContext.getBean("kunService"); KunService kunService2 = (KunService) kunApplicationContext.getBean("kunService"); GuoService guoService = (GuoService) kunApplicationContext.getBean("guoService"); GuoService guoService2 = (GuoService) kunApplicationContext.getBean("guoService"); System.out.println(kunService); System.out.println(kunService2); System.out.println(guoService); System.out.println(guoService2); } }
测试结果
com.kun.service.KunService@32e6e9c3 com.kun.service.KunService@32e6e9c3 com.kun.service.GuoService@5056dfcb com.kun.service.GuoService@6574b225
依赖注入
创建
Autowired
注解package com.spring.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * @author guokun * @date 2022/9/5 21:15 * 运行时字段注解 * 依赖注入(当前只考虑字段属性) * 先通过类型再通过字段名去获取单例bean */ @Retention(RetentionPolicy.RUNTIME) @Target(ElementType.FIELD) public @interface Autowired { }
修改
GuoService
注入KunService
package com.kun.service; import com.spring.annotation.Autowired; import com.spring.annotation.Component; import com.spring.annotation.Scope; /** * @author guokun * @date 2022/9/5 17:15 */ @Component("guoService") @Scope("prototype") public class GuoService { @Autowired private KunService kunService; public void test() { System.out.println("guoService test()"); } public KunService getKunService() { return kunService; } }
修改
createBean()
方法,实现依赖注入private Object createBean(String beanName, BeanDefinition beanDefinition) { Class<?> cla = beanDefinition.getType(); Object bean = null; try { bean = cla.getDeclaredConstructor().newInstance(); // 依赖注入 Field[] declaredFields = cla.getDeclaredFields(); for (Field field : declaredFields) { if (field.isAnnotationPresent(Autowired.class)) { field.setAccessible(true); Class<?> type = field.getType(); String typeName = Introspector.decapitalize(type.getSimpleName()); Object iocBean = getBean(typeName); if (iocBean == null) { iocBean = getBean(field.getName()); } field.set(bean, iocBean); } } } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); } return bean; }
此时在依赖注入时,需要注入的bean可能还未创建,则需要进行创建,修改
getBean()
public Object getBean(String beanName) { // 如果BeanDefinitionMap中没有对应的则说明该bean不在扫描的范围内 if (!beanDefinitionMap.containsKey(beanName)) { return null; } // 有对应的BeanDefinition Object bean = null; BeanDefinition beanDefinition = beanDefinitionMap.get(beanName); if ("prototype".equals(beanDefinition.getScope())) { // 多例 bean = createBean(beanName, beanDefinition); } else { // 单例 bean = singletonObjects.get(beanName); // 考虑还未创建的单例bean被获取时,提前创建(可能出现循环依赖) if (bean == null) { bean = createBean(beanName, beanDefinition); singletonObjects.put(beanName, bean); } } return bean; }
测试
创建测试类
IocTest1
import com.kun.config.KunAppConfig; import com.kun.service.GuoService; import com.kun.service.KunService; import com.spring.KunApplicationContext; /** * @author guokun * @date 2022/9/5 21:37 */ public class IocTest1 { public static void main(String[] args) { KunApplicationContext kunApplicationContext = new KunApplicationContext(KunAppConfig.class); GuoService guoService = (GuoService) kunApplicationContext.getBean("guoService"); System.out.println(guoService.getKunService()); } }
运行结果
com.kun.service.KunService@1efbd816
注意,此时并未处理循环依赖问题
InitializingBean
创建
InitializingBean
接口package com.spring; /** * @author guokun * @date 2022/9/5 21:43 */ public interface InitializingBean { /** * 创建Bean实例后,初始化前调用该方法 */ void afterPropertiesSet(); }
在
createBean()
的依赖注入完成之后执行InitializingBean
接口的afterPropertiesSet()
方法// 执行InitializingBean的afterPropertiesSet方法 if (bean instanceof InitializingBean) { ((InitializingBean) bean).afterPropertiesSet(); }
在
KunService
中实现InitializingBean
接口package com.kun.service; import com.spring.InitializingBean; import com.spring.annotation.Component; /** * @author guokun * @date 2022/9/5 17:15 */ @Component("kunService") public class KunService implements InitializingBean { public void test() { System.out.println("kunService test()"); } @Override public void afterPropertiesSet() { System.out.println(this + ":" + "afterPropertiesSet"); } }
测试
- 测试类
InitializingBeanTest
import com.kun.config.KunAppConfig; import com.kun.service.KunService; import com.spring.KunApplicationContext; /** * @author guokun * @date 2022/9/5 21:37 */ public class InitializingBeanTest { public static void main(String[] args) { KunApplicationContext kunApplicationContext = new KunApplicationContext(KunAppConfig.class); KunService kunService = (KunService) kunApplicationContext.getBean("kunService"); } }
- 测试结果
com.kun.service.KunService@402f32ff:afterPropertiesSet
- 测试类
BeanPostProcessor
创建
BeanPostProcessor
接口package com.spring; /** * @author guokun * @date 2022/9/5 21:53 */ public interface BeanPostProcessor { /** * bean初始化前置处理 * @param bean * @param beanName * @return */ default Object postProcessorBeforeInitialization(Object bean, String beanName) { return bean; } /** * bean初始化后置处理 * @param bean * @param beanName * @return */ default Object postProcessorAfterInitialization(Object bean, String beanName) { return bean; } }
在
ApplicationContext
中创建一个List
集合存储所有的beanPostProcessor
的bean
对象private List<BeanPostProcessor> beanPostProcessorList = new LinkedList<>();
扫描包时将实现了
BeanPostProcesso
接口的类实例化一个对象放入集合中cla.isAssignableFrom(interface.cla)
查看某个类是否实现了某个接口// 判断是否实现了BeanPostProcessor,如果实现了则放入beanPostProcessorList中 if (BeanPostProcessor.class.isAssignableFrom(loadClass)) { BeanPostProcessor beanPostProcessor = (BeanPostProcessor) loadClass.getDeclaredConstructor().newInstance(); beanPostProcessorList.add(beanPostProcessor); }
在
createBean()
的依赖注入后分别执行BeanPostProcessor
的before
与after
方法// 执行所有BeanPostProcessor的before for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) { beanPostProcessor.postProcessorBeforeInitialization(bean, beanName); } // 初始化 To Do // 执行所有BeanPostProcessor的after for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) { beanPostProcessor.postProcessorAfterInitialization(bean, beanName); }
创建类
KunPostProcessorService
实现BeanPostProcessor
package com.kun.service; import com.spring.BeanPostProcessor; import com.spring.annotation.Component; /** * @author guokun * @date 2022/9/5 22:46 */ @Component public class KunPostProcessorService implements BeanPostProcessor { @Override public Object postProcessorBeforeInitialization(Object bean, String beanName) { System.out.println(this + ":" + "postProcessorBeforeInitialization"); return bean; } @Override public Object postProcessorAfterInitialization(Object bean, String beanName) { System.out.println(this + ":" + "postProcessorAfterInitialization"); return bean; } }
测试
import com.kun.config.KunAppConfig; import com.kun.service.KunService; import com.spring.KunApplicationContext; /** * @author guokun * @date 2022/9/5 21:37 */ public class BeanPostProcessorTest { public static void main(String[] args) { KunApplicationContext kunApplicationContext = new KunApplicationContext(KunAppConfig.class); } }
测试结果
com.kun.service.KunPostProcessorService@6d78f375:postProcessorBeforeInitialization com.kun.service.KunPostProcessorService@6d78f375:postProcessorAfterInitialization com.kun.service.KunService@1810399e:afterPropertiesSet com.kun.service.KunPostProcessorService@6d78f375:postProcessorBeforeInitialization com.kun.service.KunPostProcessorService@6d78f375:postProcessorAfterInitialization
Aware
有时我们创建的Bean
可能需要注入一些Spring
中的对象,此时就可以通过Aware
来实现注入。
原理是Aware
会给对应对象设置一个set
方法来让程序员在实现类中实现设置,然后Spring
会在 IOC
执行完成普通对象的注入后 执行Aware
的方法来将Spring
的对象注入到Bean
中。
BeanNameAware
用于获取Bean
的BeanName
。
写
Aware
,BeanNameAware
接口Aware
package com.spring; /** * @author guokun * @date 2022/9/6 22:38 */ public interface Aware { }
BeanNameAware
package com.spring; /** * @author guokun * @date 2022/9/6 22:32 */ public interface BeanNameAware extends Aware { /** * 设置Bean的BeanName属性 */ void setBeanName(); }
在
createBean()
的IOC
普通对象注入后执行Aware
的方法
需要判断是否是Aware
的实例,然后一一判断是否为其他Aware
子类的实例并执行其注入方法// Aware注入Spring对象属性 if (bean instanceof Aware) { if (bean instanceof BeanNameAware) { ((BeanNameAware) bean).setBeanName(beanName); } }
KunServer
实现BeanNameAware
接口package com.kun.service; import com.spring.BeanNameAware; import com.spring.InitializingBean; import com.spring.annotation.Component; /** * @author guokun * @date 2022/9/5 17:15 */ @Component("kunService") public class KunService implements InitializingBean, BeanNameAware { private String beanName; public void test() { System.out.println("kunService test()"); } @Override public void afterPropertiesSet() { System.out.println(this + ":" + "afterPropertiesSet"); } public String getBeanName() { return beanName; } @Override public void setBeanName(String name) { this.beanName = name; } }
测试
import com.kun.config.KunAppConfig; import com.kun.service.KunService; import com.spring.KunApplicationContext; /** * @author guokun * @date 2022/9/6 22:46 */ public class BeanNameAwareTest { public static void main(String[] args) { KunApplicationContext context = new KunApplicationContext(KunAppConfig.class); KunService kunService = (KunService) context.getBean("kunService"); System.out.println("beanName:\t" + kunService.getBeanName()); } }
com.kun.service.KunPostProcessorService@6d78f375:postProcessorBeforeInitialization com.kun.service.KunPostProcessorService@6d78f375:postProcessorAfterInitialization com.kun.service.KunService@4439f31e:afterPropertiesSet com.kun.service.KunPostProcessorService@6d78f375:postProcessorBeforeInitialization com.kun.service.KunPostProcessorService@6d78f375:postProcessorAfterInitialization beanName: kunService