文章目录
1 使用注解模拟Spring的IOC容器
1.1 IOC容器的工作方式
Spring中的IOC容器用来生产Bean,所谓Bean就是一个类的对象,IOC容器让程序员创建对象时不再通过new的方式直接生成对象,而是从IOC容器中取得已经创建好了的对象
这样做最大的好处就是减少了依赖,降低了耦合,提高了程序的可维护性
IOC的使用方式是通过getBean(String BeanName)的方式获取一个对象,我们可以将IOC容器看成一个类似Map<String, Bean>的数据结构,根据类名,来获取该类的对象
由于Map拒绝键重复,默认情况下,所取得的对象都是单例的,即在项目中的任何一个类中,相同BeanName对应的Bean都是一样的,这样做可以直接传参,如Service层和Dao层用到了IOC容器中相同的对象,只需要更改Service层内对象的数据,Dao层中该对象的数据也会发生改变
1.2 模拟IOC容器需要的注解
通过XML文件或注解都可以模拟IOC容器,但是二者均有优劣,这里采用注解的方式来完成IOC容器的模拟
这里给出3个注解:
/**
* @author 雫
* @date 2021/4/16 - 14:41
* @function 作用于类
* 用于标识 该类能生成Bean
* 默认值为true 代表该类生成的简单Bean是单例
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Component {
boolean value() default true;
}
@Component 作用于类 默认值是true
拥有该注解的类,将会生成Bean
该注解将能生成Bean的类和其它类分开
默认值是true 代表默认是单例Bean false代表是非单例Bean
/**
* @author 雫
* @date 2021/4/16 - 14:41
* @function 作用于成员
* 用于标识 该成员是Bean注入时需要的一部分
* 默认值是"" 代表该成员是对象 "xxx"是该成员字符串类型的注入值
*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Autowired {
String value() default "";
}
@Autowired 作用于成员 默认值是""
拥有该注解的成员,将在生成Bean时被注入
即通过反射机制调用set方法为Bean赋值
默认值是"" 代表默认是对象 "xxx"代表是该成员的注入值
/**
* @author 雫
* @date 2021/4/16 - 14:44
* @function 作用于方法
* 代表该方法能反射执行生成复杂Bean
* 默认值是true 代表该方法生成的Bean是单例
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Bean {
boolean value() default true;
}
@Bean 作用于方法 默认值是true
拥有该注解的方法,其返回值就是Bean的类型
当该方法参数都能找到时,反射执行该方法生成Bean
默认值是true 代表默认是单例Bean false代表是非单例Bean
我们将通过扫描一个包下的所有类,来区分哪些类能产生Bean(带Component注解),进而以不同的方式生成Bean
我们将Bean分为两种:
简单Bean
带有@Component注解和@Autowired
可以通过反射直接生成Bean
复杂Bean
带有@Component注解和@Bean注解
代表该Bean由方法生成
根据该方法的参数格式,可以分为
无参复杂Bean
带参复杂Bean
1.3 生成简单Bean前的准备
我们先创建两个简单类,为它加上Component注解和Autowired注解,以后不再new一个该类对象,而是从IOC容器中直接取得该类对象
/**
* @author 雫
* @date 2021/4/16 - 14:46
* @function 生成简单Bean 生成的Bean非单例
*/
@Component(value = false)
public class Point {
@Autowired(value = "15")
private int x;
@Autowired(value = "35")
private int y;
public Point() {}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
/**
* @author 雫
* @date 2021/4/16 - 14:47
* @function 生成简单Bean 生成的Bean单例
* 其成员point是Point类型的对象
*/
@Component
public class SomeClass {
@Autowired
private Point point;
public SomeClass() {}
public Point getPoint() {
return point;
}
public void setPoint(Point point) {
this.point = point;
}
public void showPoint() {
System.out.println(this.point);
}
}
先讨论简单Bean生成的时机,选择饿汉模式还是懒汉模式,这里采用懒汉模式,当用户getBean()时再去注入生成Bean并返回
对于IOC容器的结构,仍然是一个Map:
Map<Class<?>, BeanDefinition>
键是Class<?> 采用String也可以,但调用getBean()时需要使用类的全名
值是BeanDefinition,这是一个类,用来存储生成/控制Bean的一些数据
如class对象,注入时需要反射调用成员的set方法
如object对象,存储真正的Bean,待调用时返回真正的Bean
...
BeanDefinition类:
/**
* @author 雫
* @date 2021/4/16 - 14:49
* @function 存储Bean
* 以及生成Bean所需要的class对象 和该Bean是否以存在的标志
*/
public class BeanDefinition {
private Class<?> klass;
private Object object;
private boolean complete;
private Method method;
BeanDefinition() {}
Class<?> getKlass() {
return klass;
}
void setKlass(Class<?> klass) {
this.klass = klass;
}
Object getObject() {
return object;
}
void setObject(Object object) {
this.object = object;
}
boolean isComplete() {
return complete;
}
void setComplete(boolean complete) {
this.complete = complete;
}
Method getMethod() {
return method;
}
void setMethod(Method method) {
this.method = method;
}
}
1.4 开始生成简单Bean
我们将扫描一个包下的所有文件,查看哪些类有Component注解,将这些类拿出来生成Bean,为此需要一个包扫描工具,获取包下的每个类的class对象进行处理
Java包扫描工具
BeanFactory:
/**
* @author 雫
* @date 2021/4/16 - 14:48
* @function 用于生成和存储Bean
*/
public class BeanFactory {
private static final Map<Class<?>, BeanDefinition> BEAN_POOL;
static {
BEAN_POOL = new HashMap<>();
}
/**
* @Author 雫
* @Description 扫描指定路径的包 区分简单Bean和复杂Bean分类处理
* @Date 2021/4/16 14:52
* @Param [packageName]
* @return void
**/
public static void scanPackage(String packageName) throws Exception {
new AbstractPackageScanner() {
@Override
public void dealClass(Class<?> klass) {
if(!klass.isAnnotationPresent(Component.class)) {
return;
}
try {
/*
* 处理简单Bean 即不带@Bean注解的类 直接生成一个BD存入BEAN_POOL中即可
* 等到getBean时 再进行注入 即懒汉模式
* */
BeanDefinition bd = new BeanDefinition();
Object object = klass.newInstance();
bd.setKlass(klass);
bd.setObject(object);
bd.setComplete(false);
bd.setMethod(null);
BEAN_POOL.put(klass, bd);
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {}
}
}.packageScan(packageName);
}
/**
* @Author 雫
* @Description 根据class对象从BEAN_POOL中获得对应的BD
* 再从BD中取出真正的Bean返回 返回前需要检查需要的Bean是单例还是原型
* @Date 2021/4/16 14:57
* @Param [klass]
* @return T
**/
public static <T> T getBeanByClass(Class<?> klass) throws Exception {
BeanDefinition bd = BEAN_POOL.get(klass);
if(bd == null) {
return null;
}
// 完成对简单Bean的注入
inject(bd);
Object object = bd.getObject();
// 查看该Bean是以单例方式还是原型方式返回
if(bd.getMethod() == null) {
Component component = bd.getKlass().getAnnotation(Component.class);
boolean componentValue = component.value();
if(componentValue) {
return (T) object;
} else {
return (T) bd.getKlass().newInstance();
}
}
}
/**
* @Author 雫
* @Description 简单Bean的注入
* 即通过BD中的class对象 通过反射调用set方法完成赋值
* @Date 2021/4/16 15:00
* @Param [bd]
* @return void
**/
private static void inject(BeanDefinition bd) throws Exception {
if(bd.isComplete()) {
return;
}
// 简单Bean第一次注入时 直接提前更改注入标志 这样可以避免简单Bean的循环依赖
bd.setComplete(true);
Class<?> klass = bd.getKlass();
Object object = bd.getObject();
Field[] fields = klass.getDeclaredFields();
for(Field field : fields) {
if(!field.isAnnotationPresent(Autowired.class)) {
continue;
}
Autowired autowired = field.getAnnotation(Autowired.class);
String autowiredString = autowired.value();
String fieldName = field.getName();
Class<?> fieldType = field.getType();
String fieldTypeStr = field.getType().getName();
Object fieldValue;
if(autowiredString.length() == 0) {
fieldValue = getBeanByClass(fieldType);
} else {
fieldValue = TypeParser.getValue(fieldTypeStr, autowiredString);
}
String setterMethodName = "set" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
Method setterMethod = klass.getDeclaredMethod(setterMethodName, new Class<?>[] {fieldType});
setterMethod.invoke(object, new Object[] {fieldValue});
}
}
至此,就可以当getBean(Class<?> klass)时,获取一个该类的Bean,其工作流程是:
1,扫描包下所有类,为带有Component注解的类
生成一个BeanDefinition(以下简称BD)
2,为BD赋值,将BD存入IOC容器,即BEAN_POOL中
3,当通过getBean(Class<?> klass)试图获取Bean时
从容器中取得对应的BD,开始注入
4,inject(BD bd)方法完成注入,通过遍历该类的所有成员
通过反射机制掉用带有Autowired注解的成员的set方法赋值
5,注入成功,返回注入完成的Bean
1.5 生成无参复杂Bean
生成简单Bean并不麻烦,现在来看如何生成复杂Bean,复杂Bean有两种,一种是无参复杂Bean,一种是带参复杂Bean,这里先讨论无参复杂Bean的处理方式
先创建一个类,该类中有生成无参复杂Bean的方法:
/**
* @author 雫
* @date 2021/4/16 - 15:11
* @function 可生成无参复杂Bean TypeParser类的对象
* TypeParser类是我的工具包中的一个类
*/
@Component
public class BeanConfig {
public BeanConfig() {}
@Bean
public TypeParser getTypeParser() {
TypeParser typeParser = new TypeParser();
return typeParser;
}
}
观察上述方法,其实生成无参复杂Bean也不麻烦,只需要反射执行这个方法即可,该方法执行后的返回值就是我们需要的Bean,方法自然需要反射执行,method.invoke(obj, args),方法需要依赖对象来执行,生成复杂Bean的方法,反射执行需要的对象就是这里带Component注解的类的对象,即BeanConfig类的对象
我们对BeanFactory的scanPackage()方法稍作更改,就可以直接生成无参复杂Bean
/**
* @Author 雫
* @Description 扫描指定路径的包 区分简单Bean和复杂Bean分类处理
* @Date 2021/4/16 14:52
* @Param [packageName]
* @return void
**/
public static void scanPackage(String packageName) throws Exception {
new AbstractPackageScanner() {
@Override
public void dealClass(Class<?> klass) {
if(!klass.isAnnotationPresent(Component.class)) {
return;
}
try {
/*
* 处理简单Bean 即不带@Bean注解的类 直接生成一个BD存入BEAN_POOL中即可
* 等到getBean时 再进行注入 即懒汉模式
* 而如果是复杂Bean 即带@Bean注解的方法生成的Bean 稍后检测方法分为无参和有参处理
* 且这里的object就是方法执行时 所需要的对象
* */
BeanDefinition bd = new BeanDefinition();
Object object = klass.newInstance();
bd.setKlass(klass);
bd.setObject(object);
bd.setComplete(false);
bd.setMethod(null);
BEAN_POOL.put(klass, bd);
BeanClassRelation.adjustClassRelation(klass);
// 遍历所有方法 检查方法有无 @Bean注解 且带有@Bean注解的方法被分为 无参 和 带参分开处理
Method[] methods = klass.getDeclaredMethods();
for(Method method : methods) {
if(!method.isAnnotationPresent(Bean.class)) {
continue;
}
int paraCount = method.getParameterCount();
// 无参复杂Bean方法 直接反射执行生成Bean存入BEAN_POOL中
if(paraCount == 0) {
BeanDefinition beanBD = new BeanDefinition();
beanBD.setKlass(method.getReturnType());
beanBD.setObject(method.invoke(object, new Object[] {}));
beanBD.setComplete(true);
beanBD.setMethod(method);
BEAN_POOL.put(method.getReturnType(), beanBD);
// 带参复杂Bean方法 创建依赖关系表 依赖满足后再执行
} else {
// TODO
}
}
} catch (InstantiationException | IllegalAccessException | InvocationTargetException e) {}
}
}.packageScan(packageName);
}
这样就可以生成无参复杂Bean,在生成带参复杂Bean之前,需要考虑几个问题:(这里只考虑参数是非八大基本类型的情况)
1,带参方法什么时候执行?
2,带参方法的参数是接口类型怎么办?
3,带参方法的若干个参数之间出现循环依赖怎么办?
1.6 带Bean注解的带参方法的执行时机
答:参数都能在BEAN_POOL中找到时执行
当我们扫描到该方法是一个带Bean注解的带参方法时,我们不要急着去执行它,将该方法的必要信息保存起来,为它创建一张参数依赖表,等到它依赖的参数都能在BEAN_POOL中找到时,再通过反射来执行该方法
执行该方法前,保存该方法必要信息的BeanMethodDefinition类:
/**
* @author 雫
* @date 2021/4/16 - 15:32
* @function 生成Bean的带参方法 执行时需要的数据
*/
public class BeanMethodDefinition {
private Class<?> klass;
private Object object;
private Method method;
// 缺失的参数个数
private int injectCount;
BeanMethodDefinition() {}
Class<?> getKlass() {
return klass;
}
void setKlass(Class<?> klass) {
this.klass = klass;
}
Object getObject() {
return object;
}
void setObject(Object object) {
this.object = object;
}
Method getMethod() {
return method;
}
void setMethod(Method method) {
this.method = method;
}
int getInjectCount() {
return injectCount;
}
void setInjectCount(int injectCount) {
this.injectCount = injectCount;
}
}
我们应该将BeanMethodDefinition(以下简称BMD)的对象,以及它依赖的参数存起来,构成一张表,这个表自然可以用Map完成:
Map<BeanMethodDefinition, Map<Class<?>, Integer>> METHOD_PREPARING_POOL;
键为BMD 即当前带Bean注解的带参方法想要执行需要保存的数据
值为<Map<Class<?>, Integer>> 这个Map每个键都是一个parameterType
即参数类型,值无所谓
有了这个参数依赖表,就可以得知当前方法依赖的参数有几个,这些参数的类型有哪些,但这张表还不够用,它将存储依赖尚不满足的BMD,我们需要将已满足依赖的BMD存储到一个列表中,时机到了,执行这些BMD中的method,来生成BD,存入BEAN_POOL中
已满足依赖的BMD列表
List<BeanMethodDefinition> METHOD_COMPLETE_POOL;
现在我们将
尚未满足依赖的BMD存入METHOD_PREPARING_POOL中,
将已满足依赖的BMD存入METHOD_COMPLETE_POOL中
在scanPackage()的过程,可能随时会生成新的Bean,而这些Bean可能就是BMD的参数,这时,依赖关系就发生了变化,我们需要调整依赖关系,检查BMD是否依赖于新生成的Bean,在scanPackage的过程中,每生成一个Bean,调整一次依赖关系,
将满足依赖的BMD从METHOD_PREPARING_POOL中移到METHOD_COMPLETE_POOL中
1.7 依赖关系的调整
注:调整依赖的过程中,可能还会出现新的Bean是某个BMD依赖的实现类的情况,即要考虑BMD的参数有可能是接口
当我们每生成一个Bean时,就应该及时调整依赖,我们需要根据Bean来找到所有依赖于它的BMD,很明显这也是一个Map可以完成的功能
Map<Class<?>, List<BeanMethodDefinition>> CLASS_RELATION_POOL;
每当我们检测到某个BMD依赖于某个参数时,那么同理该参数就是BMD需要的依赖,多个BMD就可以同时依赖同一个参数,构成一个列表
每当我们检测到有新生成的Bean,如果这个Bean是CLASS_RELATION_POOL中的参数,或者是CLASS_RELATION_POOL中参数的实现类,那么就可以对应的BMD列表,根据这个BMD列表找到METHOD_PREPARING_POOL去除对应的依赖个数,如果依赖为0个,则转存到METHOD_COMPLETE_POOL中
BeanMethodRelation类:
/**
* @author 雫
* @date 2021/4/16 - 15:34
* @function 存储BMD想要执行还欠缺的依赖关系 和已经满足依赖关系的BMD
*/
public class BeanMethodRelation {
private static final Map<BeanMethodDefinition, Map<Class<?>, Integer>> METHOD_PREPARING_POOL;
private static final List<BeanMethodDefinition> METHOD_COMPLETE_POOL;
static {
METHOD_PREPARING_POOL = new HashMap<>();
METHOD_COMPLETE_POOL = new ArrayList<>();
}
/**
* @Author 雫
* @Description 检测到带参方法 将方法执行时需要的数据保存到BMD中
* 建立依赖关系并检查 将已满足依赖的存入METHOD_COMPLETE_POOL中 依赖欠缺的存入METHOD_PREPARING_POOL中
* @Date 2021/4/16 15:38
* @Param [object, method]
* @return void
**/
static void addMethodRelation(Object object, Method method) {
BeanMethodDefinition bmd = new BeanMethodDefinition();
bmd.setKlass(method.getReturnType());
bmd.setObject(object);
bmd.setMethod(method);
// paraTypeSet 保存该BMD欠缺的依赖类型
Map<Class<?>, Integer> paraTypeSet = new HashMap<>();
Parameter[] parameters = method.getParameters();
for(Parameter parameter : parameters) {
if(BeanFactory.hasBean(parameter.getType())) {
continue;
}
paraTypeSet.put(parameter.getType(), 0);
BeanClassRelation.addClassRelation(parameter.getType(), bmd);
}
int injectCount = paraTypeSet.size();
bmd.setInjectCount(injectCount);
if(injectCount == 0) {
METHOD_COMPLETE_POOL.add(bmd);
} else {
METHOD_PREPARING_POOL.put(bmd, paraTypeSet);
}
}
/**
* @Author 雫
* @Description 调整某个依赖已满足的BMD的依赖数量
* 注意klass可能是某个依赖的实现类 需要检查
* @Date 2021/4/16 16:06
* @Param [relationKlass, bmd]
* @return void
**/
static void adjustMethodRelation(Class<?> klass, BeanMethodDefinition bmd) {
Map<Class<?>, Integer> paraTypeSet = METHOD_PREPARING_POOL.get(bmd);
for(Class<?> beanKlass : paraTypeSet.keySet()) {
if(beanKlass.isAssignableFrom(klass) || beanKlass == klass) {
paraTypeSet.remove(beanKlass);
bmd.setInjectCount(bmd.getInjectCount() - 1);
}
}
if(bmd.getInjectCount() == 0) {
METHOD_PREPARING_POOL.remove(bmd);
METHOD_COMPLETE_POOL.add(bmd);
}
}
static boolean hasNextBMD() {
if(METHOD_COMPLETE_POOL.isEmpty()) {
return false;
}
return true;
}
static BeanMethodDefinition nextBMD() {
if(hasNextBMD()) {
return METHOD_COMPLETE_POOL.remove(0);
}
return null;
}
/**
* @Author 雫
* @Description 根据class获取BMD
* @Date 2021/4/16 16:43
* @Param []
* @return com.coisini.ioc.core.BeanMethodDefinition
**/
static BeanMethodDefinition getBmdByClass(Class<?> klass) {
for(BeanMethodDefinition bmd : METHOD_PREPARING_POOL.keySet()) {
if(bmd.getKlass() == klass) {
return bmd;
}
}
return null;
}
/**
* @Author 雫
* @Description 获取BMD的所有未满足的依赖关系
* @Date 2021/4/16 16:45
* @Param [bmd]
* @return java.lang.String
**/
static String getBmdRelations(BeanMethodDefinition bmd) {
Map<Class<?>, Integer> paraTypeSet = METHOD_PREPARING_POOL.get(bmd);
StringBuffer relationStr = new StringBuffer();
for(Class<?> klass : paraTypeSet.keySet()) {
relationStr.append(" " + klass.getName() + " ");
}
return relationStr.toString();
}
}
BeanClassRelation:
/**
* @author 雫
* @date 2021/4/16 - 15:34
* @function 保存依赖某个Bean的BMD列表
* 当生成某个Bean时 就可以即时找到依赖它的BMD 并调整依赖关系
*/
public class BeanClassRelation {
private static final Map<Class<?>, List<BeanMethodDefinition>> CLASS_RELATION_POOL;
static {
CLASS_RELATION_POOL = new HashMap<>();
}
/**
* @Author 雫
* @Description 增加类对应的BMD依赖
* 当生成带参方法的BMD 遍历BMD中method的参数时执行
* @Date 2021/4/16 15:48
* @Param []
* @return void
**/
static void addClassRelation(Class<?> klass, BeanMethodDefinition bmd) {
if(!CLASS_RELATION_POOL.containsKey(klass)) {
CLASS_RELATION_POOL.put(klass, new ArrayList<>());
}
List<BeanMethodDefinition> relationList = CLASS_RELATION_POOL.get(klass);
relationList.add(bmd);
}
/**
* @Author 雫
* @Description 每生成一个Bean 及时调整依赖关系
* 注意新生成的Bean可能是某个依赖的实现类 即依赖可能是接口类型 需要检查
* @Date 2021/4/16 15:55
* @Param [klass]
* @return void
**/
static void adjustClassRelation(Class<?> klass) {
for(Class<?> beanKlass : CLASS_RELATION_POOL.keySet()) {
if(beanKlass.isAssignableFrom(klass) || beanKlass == klass) {
List<BeanMethodDefinition> relationList = CLASS_RELATION_POOL.get(beanKlass);
CLASS_RELATION_POOL.remove(beanKlass);
while (!relationList.isEmpty()) {
BeanMethodRelation.adjustMethodRelation(klass, relationList.remove(0));
}
}
}
}
}
每当生成新的Bean的时候,我们不但检查它是否是某个BMD的依赖参数,同时检查它是否是某个BMD的依赖参数的实现类,这样就能完成对参数是接口类型的依赖的调整
1.8 生成复杂带参Bean
有了上述调整依赖个数的方法,我们有一个METHOD_COMPLETE_POOL,这里存储着所有依赖关系已满足,等待生成Bean的BMD,接下来回到BeanFactory中,来依次取出这些BMD,并执行其中的method,生成Bean存储到BEAN_POOL中
这个方法执行的时机,就在scanPackage的最后,但是在执行该方法时,会出现新的问题:检测到方法的参数是接口类型
我们拒绝IOC容器中有多个类实现了同一个接口,因为这样会导致二义性,因此如果该参数是接口且在IOC容器中只有一个实现类,那么没有问题,但是该参数如果既是接口,又在IOC容器中存在多个实现类,那么直接抛异常
/**
* @author 雫
* @date 2021/4/16 - 16:38
* @function 参数是接口,接口实现类不唯一异常
*/
public class ImpNotOnlyOneException extends RuntimeException {
public ImpNotOnlyOneException() {
super();
}
public ImpNotOnlyOneException(String message) {
super(message);
}
public ImpNotOnlyOneException(String message, Throwable cause) {
super(message, cause);
}
public ImpNotOnlyOneException(Throwable cause) {
super(cause);
}
protected ImpNotOnlyOneException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
BeanFactory:
/**
* @Author 雫
* @Description 查询BEAN_POOL中有几个klass接口的实现类
* @Date 2021/4/16 16:34
* @Param [klass]
* @return int
**/
private static int getInterfaceImpCount(Class<?> klass) {
int impCount = 0;
for(Class<?> beanKlass : BEAN_POOL.keySet()) {
if(klass.isAssignableFrom(beanKlass)) {
impCount++;
}
}
return impCount;
}
/**
* @Author 雫
* @Description 查询某接口在BEAN_POOL中所有实现类
* @Date 2021/4/16 16:37
* @Param [klass]
* @return java.lang.String
**/
private static String getInterfaceImpStr(Class<?> klass) {
StringBuffer impStr = new StringBuffer();
for(Class<?> beanKlass : BEAN_POOL.keySet()) {
if(klass.isAssignableFrom(beanKlass)) {
impStr.append(" " + beanKlass.getName() + " ");
}
}
return impStr.toString();
}
/**
* @Author 雫
* @Description 避免参数是接口类型 由接口类型找到BEAN_POOL中的实现类
* @Date 2021/4/17 21:58
* @Param [klass]
* @return java.lang.Class<?>
**/
private static Class<?> getImpClass(Class<?> klass) {
for(Class<?> beanKlass : BEAN_POOL.keySet()) {
if(klass.isAssignableFrom(beanKlass)) {
return beanKlass;
}
}
return null;
}
/**
* @Author 雫
* @Description 执行已满足依赖的BMD
* @Date 2021/4/16 16:20
* @Param []
* @return void
**/
private static void doBeanMethod() throws Exception {
while (BeanMethodRelation.hasNextBMD()) {
BeanMethodDefinition bmd = BeanMethodRelation.nextBMD();
Method method = bmd.getMethod();
Object object = bmd.getObject();
int paraCount = method.getParameterCount();
Object[] paraList = new Object[paraCount];
Parameter[] parameters = method.getParameters();
// 构建实参数组时 要检查参数是否为接口 且查询BEAN_POOL中实现类的个数
for(int index = 0; index < paraCount; index++) {
if(parameters[index].getType().isInterface()) {
int impCount = getInterfaceImpCount(parameters[index].getType());
if(impCount > 1) {
String impStr = getInterfaceImpStr(parameters[index].getType());
throw new ImpNotOnlyOneException("Imp Not Only One --> " + impStr
+ "Are Implement The " + parameters[index].getType());
} else {
// 先找到接口对应的实现类 再根据实现类找到相应的Bean
paraList[index] = getBeanByClass(getImpClass(parameters[index].getType()));
}
} else {
paraList[index] = getBeanByClass(parameters[index].getType());
}
}
BeanDefinition bd = new BeanDefinition();
bd.setKlass(method.getReturnType());
bd.setObject(method.invoke(object, paraList));
bd.setMethod(method);
bd.setComplete(true);
BEAN_POOL.put(method.getReturnType(), bd);
BeanClassRelation.adjustClassRelation(method.getReturnType());
}
}
解决了参数是接口类型的问题后,又有新的问题:
1,循环依赖,参数间存在循环依赖,无法执行方法产生Bean,对于这种方法中存在循环依赖的问题,无法解决,但是可以定位到它依赖的参数类型,并抛出异常,告知使用者发生了循环依赖,并告知具体的依赖关系
2,试图获取没有经过注解配置的Bean,此时直接抛出一个该Bean未装载异常
/**
* @author 雫
* @date 2021/4/16 - 16:48
* @function 循环依赖异常
*/
public class RelationNotEnoughException extends RuntimeException {
public RelationNotEnoughException() {
super();
}
public RelationNotEnoughException(String message) {
super(message);
}
public RelationNotEnoughException(String message, Throwable cause) {
super(message, cause);
}
public RelationNotEnoughException(Throwable cause) {
super(cause);
}
protected RelationNotEnoughException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
/**
* @author 雫
* @date 2021/4/16 - 17:55
* @function Bean尚未装载异常
*/
public class BeanNeverLoad extends RuntimeException {
public BeanNeverLoad() {
super();
}
public BeanNeverLoad(String message) {
super(message);
}
public BeanNeverLoad(String message, Throwable cause) {
super(message, cause);
}
public BeanNeverLoad(Throwable cause) {
super(cause);
}
protected BeanNeverLoad(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
BeanFactory:
/**
* @Author 雫
* @Description 根据class对象从BEAN_POOL中获得对应的BD
* 再从BD中取出真正的Bean返回 返回前需要检查需要的Bean是单例还是原型
* @Date 2021/4/16 14:57
* @Param [klass]
* @return T
**/
public static <T> T getBeanByClass(Class<?> klass) throws Exception {
BeanDefinition bd = BEAN_POOL.get(klass);
if(bd == null) {
BeanMethodDefinition bmd = BeanMethodRelation.getBmdByClass(klass);
if(bmd == null) {
throw new BeanNeverLoad("This Bean: " + klass.getName() + " Never Load");
} else {
String relationStr = BeanMethodRelation.getBmdRelations(bmd);
throw new RelationNotEnoughException("Relation Not Enough --> " + relationStr);
}
}
// 完成对简单Bean的注入
inject(bd);
Object object = bd.getObject();
// 查看该Bean是以单例方式还是原型方式返回
if(bd.getMethod() == null) {
Component component = bd.getKlass().getAnnotation(Component.class);
boolean componentValue = component.value();
if(componentValue) {
return (T) object;
} else {
return (T) bd.getKlass().newInstance();
}
} else {
Bean bean = bd.getMethod().getAnnotation(Bean.class);
boolean beanValue = bean.value();
if(beanValue) {
return (T) object;
} else {
return (T) bd.getKlass().newInstance();
}
}
}
1.9 小结
经过上述一系列处理,终于能够生成各种Bean,并且大概能解决循环依赖和参数类型是接口的问题,通过模拟Spring的IOC,大致能了解到其工作原理,通过反射能让Java动态地处理问题,灵活地使用Map,能很好处理一对一和一对多的问题