我们前面分析很多的Spring源码,现在我们来手写一个简易的Spring源码
创建一个maven工程。
public class Test {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
UserService userService = context.getBean("UserService", UserService.class);
userService.test();
}
}
在我们的通常Spring项目中,一定有这几步,我们想要手写就得先模拟出这几个方法和类。
Autowrite注解的依赖注入实现: 遍历出类中的所有属性,循环他们进行判断是否加了Autowrite注解,通过getBean得到对象,再把得到的对象赋值给instance。(记得开启Accessible)
创建一个扫描注解 创建bean注解 一个scope判断是否是单例注解 在启动类上配置扫描注解,给扫描路径 创一个Annotationcontext类 有get bean方法。通过得到注解扫描的类,通过App扫描得到注解所需要扫描的地址,通过截取 替换路径,解析成为com.user.service字符串,把他放入到classloader.loadclass中得到class对象 判断对象上是否有component注解,得到当前bean对应的名字 (创建beandefinition描述类 里面有 scope class属性 )设置bd的class属性为当前类属性 判断当前类是否有原型bean注解 没有就设置它的描述scope为单例 有就设置它为注解上的值 最后将它们放入beandefinitionmap中 当我们在getbean的时候 传入beanName 我们在bdMap中去找 找到了则进行判断是否为单例bean 是则直接返回这里返回的bean对象都是一样的,称之为单例bean 不是则通过bd中的class类通过反射进行创建,这里每创建的bean都是不一样的 不存在就抛出异常 当然spring在启动的时候就把bean对象创建好了 我们通过循环bad.enteyset 得到bean名字和bd 判断是否是单例的,是就直接放入单例池。
package com.spring;
import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.net.URL;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
public class LuoChaoApplicationContext {
//对应AppConfig.class
private Class configClass;
//单例池 存放单例bean 确保我们得到得对象都是单例的。
private ConcurrentHashMap<String,Object> singletonObjects = new ConcurrentHashMap<>();
//存放BeanDefintion对象的HashMap
private ConcurrentHashMap<String,BeanDefinition> beanDefinitionMap = new ConcurrentHashMap<>();
//存放BeanPostProcessor集合
private List<BeanPostProcessor> beanPostProcessorList = new ArrayList<>();
public LuoChaoApplicationContext(Class configClass) {
this.configClass = configClass;
//解析配置类
// Compontent注解---》扫描路径---》扫描---》BeanDefinition---》beanDefinitionMap
sacn(configClass);
//在我们启动的时候就要把所有的单例bean创建好
/*
entrySet()的返回值也是返回一个Set集合,此集合的类型为Map.Entry。
Map.Entry是Map声明的一个内部接口,此接口为泛型,定义为Entry<K,V>。
它表示Map中的一个实体(一个key-value对)。接口中有getKey(),getValue方法。
*/
for (Map.Entry<String,BeanDefinition> entry : beanDefinitionMap.entrySet()) {
//得到bean的名字
String beanName = entry.getKey();
BeanDefinition beanDefinition = entry.getValue();
//判断是否是单例bean
if (beanDefinition.getScope().equals("singleton")){
Object bean = createBean(beanName,beanDefinition);
//是单例的把它放到单例池里面去
singletonObjects.put(beanName,bean);
}
}
}
//对应getBean方法
public Object getBean(String beanName){
//判断传进来的这个名字有没有对应的bean描述
if (beanDefinitionMap.containsKey(beanName)){
BeanDefinition beanDefinition = beanDefinitionMap.get(beanName);
//判断名字对象的对象是否是单例的
if (beanDefinition.getScope().equals("singleton")){
//从单例池中拿到这个对象
Object o = singletonObjects.get(beanName);
return o;
}else {
//原型bean 创建bean对象。
Object bean = createBean(beanName,beanDefinition);
return bean;
}
}else {
//不存在
throw new NullPointerException();
}
}
// 通过beanDefinition描述创建一个对象
public Object createBean(String beanName ,BeanDefinition beanDefinition){
//得到bean的class对象
Class clazz = beanDefinition.getClazz();
//通过反射调用无参构造进行bean的创建
try {
Object instance = clazz.getDeclaredConstructor().newInstance();
//依赖注入 (不考虑循环依赖问题)
// 得到类中的属性
Field[] declaredFields = clazz.getDeclaredFields();
for (Field declaredField : clazz.getDeclaredFields()) {
//判断是否加了自动注入注解。
if (declaredField.isAnnotationPresent(Autowired.class)){
//此处我们先只判断byName 我们调用getBean得到对象
Object bean = getBean(declaredField.getName());
//判断required是否为false
Autowired annotation = declaredField.getAnnotation(Autowired.class);
boolean required = annotation.required();
//判断bean为空并且required值为false 无法注入值
if (bean==null && required){
//抛出异常
throw new RuntimeException();
}
//实际上setAccessible是启用和禁用访问安全检查的开关
declaredField.setAccessible(true);
// 将bean对象赋值给instance属性。
declaredField.set(instance,bean);
}
}
//判断是否实现了BeanNameAware接口 也叫做回调
if (instance instanceof BeanNameAware){
((BeanNameAware) instance).setBeanName(beanName);
}
//遍历出所有存放的beanPostProcessor
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
//将对象和名字传入 进行初始化前的操作
instance = beanPostProcessor.postProcessBeforeInitialization(instance,beanName);
}
//判断是否实现了InitializingBean接口 初始化
if (instance instanceof InitializingBean){
try {
((InitializingBean) instance).afterPropertiesSet();
} catch (Exception e) {
e.printStackTrace();
}
}
//遍历出所有存放的beanPostProcessor
for (BeanPostProcessor beanPostProcessor : beanPostProcessorList) {
//将对象和名字传入 进行初始化后的操作
instance = beanPostProcessor.postProcessAfterInitialization(instance,beanName);
}
//BeanPostProcessor
//直接返回创建的bean对象
return instance;
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
}
return null;
}
private void sacn(Class configClass) {
//拿到配置类进行解析
//解析ComponentScan注解拿到扫描路径进行扫描
ComponentScan componentScanAnnotation = (ComponentScan) configClass.getDeclaredAnnotation(ComponentScan.class);
//拿到注解扫描得路径
String path = componentScanAnnotation.value();
//进行扫描类上面是否加载了ComponentScan注解
/**
* Bootstrap---》jre/lib
* ext----》jre/ext/lib
* App----》classpath
*/
ClassLoader classLoader = LuoChaoApplicationContext.class.getClassLoader();//得到得就是app
URL resource = classLoader.getResource("com/luochao/service");
//得到service目录
File file = new File(resource.getFile());
//判断是不是一个目录
if (file.isDirectory()){
File[] files = file.listFiles();
for (File file1 : files) {
//E:\code\springBychaoluo\target\classes\com\luochao\service\UserService.class
System.out.println(file1.getAbsolutePath());
/*
利用类加载加载class对象
我们要需要得不是所有得路径,我们只需要com.luochao.service.UserService路径
所以我们进行分解路径
*/
String fileName = file1.getAbsolutePath();
//判断是.class文件才进行截取替换
if (fileName.endsWith(".class")){
String className = fileName.substring(fileName.indexOf("com"), fileName.indexOf(".class"));
//com.luochao.service.UserService
className = className.replace("\\", ".");
System.out.println(className);
try {
Class<?> aClass = classLoader.loadClass(className);
//判断类上是否有Component注解
if (aClass.isAnnotationPresent(Component.class)){
//表示当前这个类是一个bean
//解析类,判断当前bean是单例bean,还是原型bean 还是prototype的bean
// BeanDefinition bean的定义
//扫描到了LuoChaoBeanPostProcessor进行是否有实现BeanPostProcessor
//判断当前的aclass是否实现了BeanPostProcessor接口
if (BeanPostProcessor.class.isAssignableFrom(aClass)){
//利用反射得到对象 在spring是使用getBean的方法执行的 使得在BeanPostProcessor中我们也可以自动注入bean对象 但是这里我们就用简单的办法容易理解。
// String name = aClass.getName();
// BeanPostProcessor instance = (BeanPostProcessor) getBean(name);
// beanDefinitionMap.put(name,beanDefinition);
BeanPostProcessor instance = (BeanPostProcessor) aClass.getDeclaredConstructor().newInstance();
//存放到集合中
beanPostProcessorList.add(instance);
}
Component componentAnnotation = aClass.getDeclaredAnnotation(Component.class);
//当前bean类所对应的名字
String beanName = componentAnnotation.value();
//表示bean的一个定义
BeanDefinition beanDefinition = new BeanDefinition();
//给beandefinition类的class属性设置值为当前类属性
beanDefinition.setClazz(aClass);
//判断是否存在scope注解
if (aClass.isAnnotationPresent(Scope.class)){
//原型bean
Scope scopeAnnotation = aClass.getDeclaredAnnotation(Scope.class);
beanDefinition.setScope(scopeAnnotation.value());
}else {
//单例bean 设置它对应的描述为单例的
beanDefinition.setScope("singleton");
}
//存放拿到的beanName
beanDefinitionMap.put(beanName,beanDefinition);
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
} catch (InstantiationException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
}
public class BeanDefinition {
//bean的类型
private Class clazz;
//是否是原型bean
private String scope;
public Class getClazz() {
return clazz;
}
public void setClazz(Class clazz) {
this.clazz = clazz;
}
public String getScope() {
return scope;
}
public void setScope(String scope) {
this.scope = scope;
}
}
//Bean的描述类
package com.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//自动注入
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD,ElementType.FIELD})
public @interface Autowired {
String value() default "";
boolean required() default true;
}
回调
package com.spring;
//回调
public interface BeanNameAware {
void setBeanName(String name);
}
package com.spring;
//AOP的最终归宿
public interface BeanPostProcessor {
//初始化前
Object postProcessBeforeInitialization(Object bean, String beanName);
//初始化后
Object postProcessAfterInitialization(Object bean, String beanName);
}
package com.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//生成bean注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
String value() default "";
}
package com.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//扫描注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ComponentScan {
String value();
}
package com.spring;
//初始化
public interface InitializingBean {
void afterPropertiesSet() throws Exception;
}
package com.spring;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
//原型bean标签
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Scope {
String value();
//单例bean是指我们在测试类中通过getbean多次得到得对象是同一个 原型bean得到得则是不同得对象
}
package com.luochao.service;
import com.spring.BeanPostProcessor;
import com.spring.Component;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//将具体的AOP代理逻辑封装成一个LuoChaoBeanPostProcessor放入Spring容器中
@Component
public class LuoChaoBeanPostProcessor implements BeanPostProcessor {
@Override
public Object postProcessBeforeInitialization(Object bean, String beanName) {
if (beanName.equals("userService")){
System.out.println("初始化前");
((UserService)bean).setBeanName("我是帅哥");
}
return bean;
}
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) {
System.out.println("初始化后");
//模拟简易的AOP 这里就可以判断是否要aop
if (beanName.equals("userService")){
/*
JDK动态代理生成一个代理对象
在spring源码中 开启Aop就是在Spring容器中生成一个BeanPostProcessor的Bean对象
放到Spring容器中去
*/
Object proxyInstance = Proxy.newProxyInstance(LuoChaoBeanPostProcessor.class.getClassLoader(), bean.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//找到jionpoint 切点
System.out.println("AOP代理逻辑");
// 执行bean中的方法进行代理
return method.invoke(bean,args);
}
});
//代理对象
return proxyInstance;
}
return bean;
}
}
package com.luochao.service;
import com.spring.Component;
@Component("peopleService")
public class PeopleService {
}
package com.luochao.service;
public interface UserService {
void test();
void setBeanName(String beanName);
}
package com.luochao.service;
import com.spring.Autowired;
import com.spring.Component;
import com.spring.InitializingBean;
@Component("userService")
public class UserServiceImpl implements UserService {
@Autowired
private PeopleService peopleService;
private String beanName;
public void setBeanName(String beanName) {
this.beanName = beanName;
}
// Aware 回调
// @Override
// public void setBeanName(String name) {
// beanName = name;
// }
public void test(){
System.out.println(peopleService);
System.out.println(beanName);
}
// //初始化
// @Override
// public void afterPropertiesSet() throws Exception {
// System.out.println("初始化");
// }
}
package com.luochao;
import com.spring.ComponentScan;
// 扫描启动类
@ComponentScan("com.luochao.service")
public class AppConfig {
}
package com.luochao;
import com.luochao.service.UserService;
import com.luochao.service.UserServiceImpl;
import com.spring.LuoChaoApplicationContext;
public class Test {
public static void main(String[] args) {
LuoChaoApplicationContext luoChaoApplicationContext = new LuoChaoApplicationContext(AppConfig.class);
UserService userService = (UserService) luoChaoApplicationContext.getBean("userService");
userService.test();
//1.代理对象 2.业务test
}
}
至此我们模拟了Spring的扫描bean 并且注入bean 简易的Aop 简易的回调 还有单例池。后面继续完善。
迈出这一小步,一定能跨上山巅。