手写Spring(二)
上一节 手写Spring(一)做了一些准备工作,并且写了Spring启动时候是如何扫描、加载类的,最后通过getBean()
方法获取bean
依赖注入
bean的单例还是原型只是作用域区别,但是创建bean都是同样的步骤。在补充createBean()
这个方法之前我们在service层新加一个OrderService
@Component("orderService")
public class OrderService {
}
在原来的UserService
新增一个属性
@Component("userService")
//@Scope("prototype")
public class UserService {
@Autowired
private OrderService orderService;
}
按照Spring运行,在测试方法中获取userService
这个对象,那么它的orderService
属性应该是已经被赋值的。
上节写到createBean()
方法中通过构造器创建实例,那么实例的属性现在都是空,下面就要进行依赖注入
private Object createBean(String beanName, BeanDefinition beanDefinition) {
Class clazz = beanDefinition.getClazz();
Object instance = null;
try {
instance = clazz.getDeclaredConstructor().newInstance();
// 依赖注入
// 1.找到属性
for (Field declaredField : clazz.getDeclaredFields()) {
// 2.判断属性有没有@Autowired注解
if (declaredField.isAnnotationPresent(Autowired.class)) {
Autowired annotation = declaredField.getAnnotation(Autowired.class);
// 3.通过该属性的名字拿到bean
Object bean = getBean(declaredField.getName());
// 如果@Autowired属性required=true 并且获取的bean为空
if (annotation.require() && bean == null) {
throw new NullPointerException();
}
// 4.设置属性
declaredField.setAccessible(true);
declaredField.set(instance, bean);
}
}
return instance;
}
Aware回调
比如UserService
有一个属性beanName
,创建对象时候我们希望给这个对象赋值一个该bean的名字,Spring中有一个接口叫BeanNameAware
就是用来给对象赋名字属性的。
我们现在开始模拟它,首先写一个BeanNameAware
接口
public interface BeanNameAware {
void setBeanName(String name);
}
UserService
实现这个BeanNameAware
接口
@Component("userService")
//@Scope("prototype")
public class UserService implements BeanNameAware{
@Autowired
private OrderService orderService;
private String beanName;
@Override
public void setBeanName(String name) {
beanName = name;
}
public void print(){
System.out.println(orderService);
System.out.println(beanName);
}
}
那么在创建bean,依赖注入后,可以判断实例是否实现了BeanNameAware
,从而把beanName
赋上去
// Aware回调
if (instance instanceof BeanNameAware){
((BeanNameAware)instance).setBeanName(beanName);
}
初始化机制
Aware回调后,创建bean还做了什么,了解Spring的可能知道还有一步叫InitializingBean
public interface InitializingBean {
void afterPropertiesSet();
}
UserService
实现这个InitializingBean
接口
@Component("userService")
//@Scope("prototype")
public class UserService implements BeanNameAware , InitializingBean {
@Autowired
private OrderService orderService;
private String beanName;
@Override
public void setBeanName(String name) {
beanName = name;
}
@Override
public void afterPropertiesSet() {
// 可以验证属性是否为空/属性赋值等是否符合要求...
System.out.println("After properties set");
}
public void print(){
System.out.println(orderService);
System.out.println(beanName);
}
}
同样在createBean()
的Aware回调方法之后增加初始化的步骤
// 初始化 if (instance instanceof InitializingBean){ ((InitializingBean)instance).afterPropertiesSet(); }
BeanPostProcessor
之前的实例化bean、依赖注入、回调、初始化其实都是在创建bean的过程中,假设程序员需要在实例化之后去做一些事情,或者之前做一些处理,又或者我们需要在初始化之前、之后做一些处理,那么就希望Spring提供一些方法来让程序员可以自己去扩展bean创建过程中做的事情
BeanPostProcessor
public interface BeanPostProcessor { Object postProcessBeforeInitialization(Object bean, String beanName); Object postProcessAfterInitialization(Object bean, String beanName);}
定义一个处理类实现BeanPostProcessor
,当然它也是bean需要添加到Spring容器中
@Componentpublic class MyBeanPostProcessor implements BeanPostProcessor { @Override public Object postProcessBeforeInitialization(Object bean, String beanName) { System.out.println("before initialization..."); // 对特定的bean进行一些处理 if (beanName.equals("userService")){ ((UserService)bean).setBeanName("userService1"); } return bean; } @Override public Object postProcessAfterInitialization(Object bean, String beanName) { System.out.println("after initialization..."); return bean; }}
MyApplicationContext
中添加处理类列表属性
private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();
在扫描@Component
时添加如下逻辑,在扫描的时候将处理类(xxxProcessor)实例化并添加到列表。
【注意】这里的实例化BeanPostProcessor
用的是无参构造器的方式,而Spring中用的是Spring自己的getBean()
方法,这样做的好处是xxxProcessor处理类中如果有@Autowired属性时候可以进行注入!并且Spring中xxxProcessor本身的创建过程是不需要有beforeProcessor
或afterProcessor
的!
//clazz对象是否实现了BeanPostProcessor接口if (BeanPostProcessor.class.isAssignableFrom(clazz)) { try { BeanPostProcessor instance = (BeanPostProcessor)clazz.getDeclaredConstructor().newInstance(); beanPostProcessorList.add(instance); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } catch (NoSuchMethodException e) { e.printStackTrace(); }}
createBean()
方法初始化前,初始化后就可以用处理类来进行对bean的处理了
// BeanPostProcessor --> 初始化前 for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) { instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName); } // 初始化 if (instance instanceof InitializingBean){ ((InitializingBean)instance).afterPropertiesSet(); } // BeanPostProcessor -->初始化后 for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) { instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName); }
我这里处理器的逻辑是把beanName更改为userService1
,可以看到结果雀食也改了!
但是也有不完善的地方就是,实现了BeanPostProcessor接口的处理类也打印了初始化前、后这样的步骤,也被注入到了BeanDefinition中
*AOP实现原理
Spring的AOP其实就是利用上面的BeanPostProcessor
来实现,并且是在初始化后来实现。比如之前我们写到在UserService
中有一个print()
方法,假如我想要在调用这个方法之前打印一个log,该怎么实现呢?
需要利用刚才的BeanPostProcessor
的初始化后来进行,因为创建了bean之后才会调用方法,所以log打印的时机应该在初始化bean之后,调用方法之前。
【注意】初始化后为创建bean的最后一步,而初始化后返回的对象将被放入单例池
MyBeanPostProcessor
的初始化后处理逻辑中用jdk的动态代理来生成代理对象,后续代理对象proxyInstance
执行某个方法(invoke中的method
)时,先执行代理逻辑,之后通过反射的方式基于原始bean
(即被代理bean)执行对应的业务方法(本例为print()
方法)
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("after initialization...");
if (beanName.equals("userService")) {
// 返回代理对象
Object proxyInstance = Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(),
bean.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理逻辑");// 找切点
// bean对象调用对应的方法
return method.invoke(bean, args);
}
});
return proxyInstance;
}
return bean;
}
本例只是简单编写AOP
对于Spring中,初始化后处理对于某一个bean要不要进行AOP也要判断,执行代理逻辑的时候肯定要判断哪些要执行,也就是找切点
总结
到此为止bean的生命周期大致已经编写完成
整个流程:
- 判断类需要创建bean
- 执行创建bean
- 依赖注入
- Aware回调
- 初始化机制
- BeanPostProcessor 初始化过程的处理
- 返回bean
- 将bean加入单例池
主要代码
MyBeanPostProcessor
public class MyApplicationContext {
private Class configClass;
/**
* 单例池
*/
private ConcurrentHashMap<String, Object> singletonObjects = new ConcurrentHashMap<>();
/**
* <beanName,BeanDefinition>信息
*/
private ConcurrentHashMap<String, BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();
public MyApplicationContext(Class configClass) {
this.configClass = configClass;
// 解析配置类,并不是解析限定符、属性,而是解析类上的注解
// ComponentScan ---> 扫描路径 ---> 扫描
scan(configClass);
// 创建bean对象
for (Map.Entry<String, BeanDefinition> entry : beanDefinitionMap.entrySet()) {
String beanName = entry.getKey();
BeanDefinition beanDefinition = entry.getValue();
if (beanDefinition.getScope().equals("singleton")) {
Object bean = createBean(beanName, beanDefinition);
singletonObjects.put(beanName, bean);
}
}
}
private Object createBean(String beanName, BeanDefinition beanDefinition) {
Class clazz = beanDefinition.getClazz();
Object instance = null;
try {
instance = clazz.getDeclaredConstructor().newInstance();
// 依赖注入
// 1.找到属性
for (Field declaredField : clazz.getDeclaredFields()) {
// 2.判断属性有没有@Autowired注解
if (declaredField.isAnnotationPresent(Autowired.class)) {
Autowired annotation = declaredField.getAnnotation(Autowired.class);
// 3.通过该属性的名字拿到bean
Object bean = getBean(declaredField.getName());
// 如果@Autowired属性required=true 并且获取的bean为空
if (annotation.require() && bean == null) {
throw new NullPointerException();
}
// 4.设置属性
declaredField.setAccessible(true);
declaredField.set(instance, bean);
}
}
// Aware回调
if (instance instanceof BeanNameAware){
((BeanNameAware)instance).setBeanName(beanName);
}
// BeanPostProcessor --> 初始化前
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
instance = beanPostProcessor.postProcessBeforeInitialization(instance, beanName);
}
// 初始化
if (instance instanceof InitializingBean){
((InitializingBean)instance).afterPropertiesSet();
}
// BeanPostProcessor -->初始化后
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
instance = beanPostProcessor.postProcessAfterInitialization(instance, beanName);
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return instance;
}
private void scan(Class configClass) {
ComponentScan componentScanAnnotation = (ComponentScan) configClass.getAnnotation(ComponentScan.class);
String path = componentScanAnnotation.value(); // 扫描路径 com.wangqun.service
// 扫描
// 包下面有些不是我们需要加载的类如XxUtil,所以我们要先拿到包下面的所有类,判断类上面是否有@Component注解
// 那么如何拿到所有类呢???
// BootStrap -----> jre/lib
// Ext -----> jre/ext/lib
// App -----> classpath 例如:/Users/wangqun03/Projects/HandWritting/Spring/target/classes com.wangqun.Test
ClassLoader classLoader = MyApplicationContext.class.getClassLoader(); // app
path = path.replace(".", "/");
URL resource = classLoader.getResource(path);// 相对路径,相对的是classpath
File file = new File(resource.getFile());
if (file.isDirectory()) {// 判断是否是目录
File[] files = file.listFiles();// 获得目录下的所有文件
for (File f : files) {
String absolutePath = f.getAbsolutePath();// 获得文件的绝对路径 这里是编译后的target/classes下的绝对路径
// 如果是类文件才处理
if (absolutePath.endsWith(".class")) {
String name = toFullQualifiedName(absolutePath);// 需要将绝对路径变成全限定名
try {
Class<?> clazz = classLoader.loadClass(name);// 通过类全限定名加载类
if (clazz.isAnnotationPresent(Component.class)) {
// 表示当前这个类是一个Bean
// 解析类,判断单例还是原型 ----> BeanDefinition
//clazz对象是否实现了BeanPostProcessor接口
if (BeanPostProcessor.class.isAssignableFrom(clazz)) {
try {
BeanPostProcessor instance = (BeanPostProcessor)clazz.getDeclaredConstructor().newInstance();
beanPostProcessorList.add(instance);
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
}
Component componentAnnotation = clazz.getAnnotation(Component.class);
String beanName = componentAnnotation.value();
// bean的定义
BeanDefinition beanDefinition = new BeanDefinition();
beanDefinition.setClazz(clazz);
if (clazz.isAnnotationPresent(Scope.class)) {
Scope scopeAnnotation = clazz.getDeclaredAnnotation(Scope.class);
beanDefinition.setScope(scopeAnnotation.value());
} else {
beanDefinition.setScope("singleton");
}
// 将bean的描述放入map
beanDefinitionMap.put(beanName, beanDefinition);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
}
}
/**
* 绝对路径变为全限定名
*
* @param absolutePath 绝对路径
* @return 全限定名
*/
private String toFullQualifiedName(String absolutePath) {
int com = absolutePath.indexOf("com");
int point = absolutePath.indexOf(".");
// 去掉.Class
String substring = absolutePath.substring(0, point);
// 去掉com之前
substring = substring.substring(com);
// 替换
substring = substring.replace("/", ".");
return substring;
}
public Object getBean(String beanName) {
if (beanDefinitionMap.containsKey(beanName)) {
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
if (beanDefinition.getScope().equals("singleton")) {
Object o = singletonObjects.get(beanName);
return o;
} else {
// 创建Bean对象
return createBean(beanName, beanDefinition);
}
} else {
throw new NullPointerException("Bean " + beanName + " not exists");
}
}
}
BeanPostProcessor
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
System.out.println("before initialization...");
// 对特定的bean进行一些处理
if (beanName.equals("userService")) {
((UserServiceImpl) bean).setBeanName("userService1");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("after initialization...");
if (beanName.equals("userService")) {
// 返回代理对象
Object proxyInstance = Proxy.newProxyInstance(MyBeanPostProcessor.class.getClassLoader(),
bean.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("代理逻辑");// 找切点
return method.invoke(bean, args);
}
});
return proxyInstance;
}
return bean;
}
}