【Java】模拟Sping,实现其IOC和AOP核心(一)

在这里我要实现的是Spring的IOC和AOP的核心,并且有关IOC的实现,注解+XML能混合使用!java

参考资料:
IOC:控制反转(Inversion of Control,缩写为IoC),是面向对象编程中的一种设计原则,能够用来减低计算机代码之间的耦合度。其中最多见的方式叫作依赖注入(Dependency Injection,简称DI),还有一种方式叫“依赖查找”(Dependency Lookup)。经过控制反转,对象在被建立的时候,由一个调控系统内全部对象的外界实体,将其所依赖的对象的引用传递给它。也能够说,依赖被注入到对象中。
AOP:Aspect Oriented Programming的缩写,意为:面向切面编程,经过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。
(以上是度娘给出的说法,能够看到这样的说法很不容易让人理解,过于官方化,下面是个人理解)spring

IOC:咱们平时在写Java程序时,总要经过new的方式来产生一个对象,对象的生死存亡是与咱们直接挂钩的,咱们须要它时,就new一个,不须要他时就经过GC帮咱们回收;控制反转的意思就是将对象的生死权交给第三方,由第三方来生成和销毁对象,而咱们只在须要时从第三方手中取获取,其他无论,这样,对象的控制权就在第三方手里,咱们只有使用权!这就是所谓的控制反转!
在Spring中,提供了XML文件配置和注解的方式来向第三方代表咱们须要第三方帮咱们建立什么对象,Spring就是这个第三方!它负责经过XML文件的解析或者包扫描的方式,找到咱们给出的映射关系,利用反射机制,在其内部帮咱们“new”出对象,再存储起来,供咱们使用!编程

AOP :就是动态代理的体现,在Spring中就是利用JDKProxy或者CGLibProxy技术,对方法进行拦截!
好比说有一个叫作fun()的方法,咱们在其执行先后对其拦截:缓存

 

就像这样,fun当作是纵向的线,那么就至关于用平面把这条线截断了!app

 

有了上面的铺垫,咱们能够大概知道,Sping的IOC和AOP能够帮咱们建立并管理对象,能够对对象的方法进行拦截,那么这两个技术合在一块儿,就能够达到自动帮咱们建立、管理、并对对象进行拦截!ide

下面先给出我简化的SpringIOC容器框图:
模拟的IOC框图函数

这是我简化后的IOC框图,实际上的SpringIOC是很是庞大的,里面包含了许多接口,以及继承关系,它把要处理的事务区分的很是细腻,将问题由大化小,层层递减,把面向接口,高内聚低耦合体现的淋漓尽致。
Spring提供了注解和Xml方式的注入,因此后面会有两个分支,分别处理注解和XML文件的配置!工具

BeanFactory:
在别的地方说法是一个最底层容器,其实不要被其“误导”,在我这它仅仅只是一个接口,只提供了最基础的一些方法,而方法的具体实现就须要真正的高级容器了!代码以下:ui

 1 public interface BeanFactory {  2     String FACTORY_BEAN_PREFIX = "&";  3     Object getBean(String var1) throws BeansException;  4     <T> T getBean(String var1, Class<T> var2) throws BeansException;  5     <T> T getBean(Class<T> var1) throws BeansException;  6     Object getBean(String var1, Object... var2) throws BeansException;  7     <T> T getBean(Class<T> var1, Object... var2) throws BeansException;  8     boolean containsBean(String var1);  9     boolean isSingleton(String var1) throws NoSuchBeanDefinitionException; 10     boolean isPrototype(String var1) throws NoSuchBeanDefinitionException; 11     boolean isTypeMatch(String var1, Class<?> var2) throws NoSuchBeanDefinitionException; 12     Class<?> getType(String var1) throws NoSuchBeanDefinitionException; 13  String[] getAliases(String var1); 14 }

(这里我直接挪用了Spring的源码,因为是模拟实现,因此后面只实现了其getBean的方法)this

 

ApplicationContext:
在别的地方的说法是一个高级容器,其实,它仍是一个接口,只不过在源码中其继承了许多接口(核心仍是BeanFactory),是一个集大成者,提供了远比BeanFactory更多的功能。但目前所要实现的核心暂时用不上它,因此暂时留一个空接口吧...

1 public interface ApplicationContext extends BeanFactory { 2     // TODO
3 }

说到这里,就不能往下继续了,由于在上面咱们看到的,所谓的“容器”,仅仅是定义了接口,彻底不能装东西啊,还有,所谓的容器里又要装什么?这里就要引入Bean!

Bean:
其实就是IOC容器里存放的东西!前面我说过,Spring会根据咱们给出的映射关系,帮咱们建立对象并存储起来,那么是否这个对象就是Bean?是!但也不是!若是说Spring仅仅只是帮咱们管理对象,那么它的功能也太单一了,那么,如今不得再也不次提到前面说过的AOP!
前面说到Spring中的AOP使用了JDKProxy和CGLibProxy这两种代理技术,这两种技术的目的都是产生代理对象,对方法进行拦截。那么,是否这个代理对象就是咱们的Bean?不彻底是!Bean实际上是原对象+代理对象!先不急,看到后面就会明白!

下面介绍两种动态代理技术:
JDKProxy
使用JDK代理,其所代理的类,必需要实现某一个接口:

 1 @SuppressWarnings("unchecked")  2 public <E> E getJDKProxy(Class<?> klass, Object tagObject) {  3     return (E) Proxy.newProxyInstance(klass.getClassLoader(),  4  klass.getInterfaces(),  5             new InvocationHandler() {  6  @Override  7                 public Object invoke(Object proxy, Method method, Object[] args)  8                         throws Throwable {  9                     // TODO 置前拦截,可对参数args进行判断
10                     Object result = null; 11                     try { 12                         result = method.invoke(tagObject, args); 13                     } catch (Exception e) { 14                         // TODO 对异常进行拦截
15                         throw e; 16  } 17                     // TODO 置后拦截,可对方法返回值进行修改
18                     return result; 19  } 20  }); 21 }

使用JDK代理的话就不得不传入一个原始对象,因此若是不考虑CGLib代理,那么Bean就是原始对象+代理对象!

 

CGLibProxy:
使用CGLib代理,是让被代理的类做为代理对象的父类,故原类不能被final修饰,也不能对final修饰的方法拦截!

如下是网上绝大多数人给出的用法:

 1 @SuppressWarnings("unchecked")  2 public <E> E getCGLibProxy(Class<?> klass) {  3     Enhancer enhancer = new Enhancer();  4     enhancer.setSuperclass(klass); // 从这里能够明显看到,让被代理的类做为了代理对象的父类
 5     enhancer.setCallback(new MethodInterceptor() {  6  @Override  7         public Object intercept(Object proxyObject, Method method, Object[] args, MethodProxy methodProxy)  8                 throws Throwable {  9             // TODO 置前拦截,可对参数args进行判断
10             Object result = null; 11             try { 12                 result = methodProxy.invokeSuper(proxyObject, args); 13             } catch (Exception e) { 14                 // TODO 对异常进行拦截
15                 throw e; 16  } 17             // TODO 置后拦截,可对方法返回值进行修改
18             return result; 19  } 20  }); 21     return (E) enhancer.create(); 22 }

这种方式是没错,可是不适用于后面要作的,至于缘由,后面分析到了就会明白!
因此使用以下方式:

 1 @SuppressWarnings("unchecked")  2 public <E> E getCGLibProxy(Class<?> klass, Object tagObject) {  3     Enhancer enhancer = new Enhancer();  4  enhancer.setSuperclass(klass);  5     enhancer.setCallback(new MethodInterceptor() {  6  @Override  7         public Object intercept(Object proxyObject, Method method, Object[] args, MethodProxy methodProxy)  8                 throws Throwable {  9             // TODO 置前拦截,可对参数args进行判断
10             Object result = null; 11             try { 12                 result = method.invoke(tagObject, args); 13             } catch (Exception e) { 14                 // TODO 对异常进行拦截
15                 throw e; 16  } 17             // TODO 置后拦截,可对方法返回值进行修改
18             return result; 19  } 20  }); 21     return (E) enhancer.create(); 22 }

因为是模拟实现,后面就所有采用CGLib代理!
能够看到以上面这种方式进行CGLib代理就须要原始对象,那么前面说到的Bean就必须是原对象+代理对象!
固然我知道以invokeSuper那种方式是不须要原始对象,可是缘由不是由于Bean,还在后面!

综上,Bean的定义以下:

1 public interface BeanElement { 2     <E> E getProxy(); 3  Object getObject(); 4     boolean isDI(); // 用于之后判断是否完成注入
5 }

在这里我把BeanElement定义为了一个接口,后面会产生两个分支,会产生两种不一样处理方式的Bean,用接口更灵活,耦合也低!

如今知道了Bean究竟是什么,咱们就能够往下继续进行:


AbstractApplicationContext:
ApplicationContext的具体实现类,但它是一个抽象类,只能实现部分功能,日后在它的基础上还要分化成两支,那么,把全部的Bean存在这里面再合适不过了!

 1 public abstract class AbstractApplicationContext implements ApplicationContext {  2     protected static final Map<String, String> beanNameMap;  // key : id value : className
 3     protected static final Map<String, BeanElement> beanMap; // key : className value : Bean
 4     protected AopFactory aopFactory; // Aop工厂,生产代理对象
 5     
 6     static {  7         beanNameMap = new HashMap<>();  8         beanMap = new HashMap<>();  9  } 10     
11     protected AbstractApplicationContext() { 12         aopFactory = new AopFactory(); 13         // 设置切面
14  aopFactory.setAdvice( 15                 (new AdviceHander()) 16                 .setIntercepterFactory(new IntercepterLoader())); 17  } 18     
19     protected void add(String id, String className, BeanElement bean) throws BeansException { 20         if (beanMap.containsKey(className)) { 21             // TODO 能够抛异常!
22             return; 23  } 24  beanMap.put(className, bean); 25         if (id.length() <= 0) return; 26         if (beanNameMap.containsKey(id)) { 27             throw new BeansException("bean:" + id + "已定义!"); 28  } 29  beanNameMap.put(id, className); 30  } 31 }

其中的aopFactory是代理工厂,负责生产代理,会在后面给出,先不急。
能够看到,AbstractApplicationContext这个类持有了两张静态的map,第一组是用来存取Bean的别名(id),第二组用来存放真正的Bean,这就是咱们真正意义上的容器,因为其map都是static修饰的,在类加载的时候就存在了,因此日后有别的类继承它时,这两个map是共享的!只增长了一个add方法,只要是继承自它的子类,都会经过这种方式添加Bean!而且这个类是protected的,不对外提供使用!

 

咱们先进行左边的分支,用注解的方式完成IOC
这里说的注解都是自定义注解,属于RUNTIME,就必须经过反射机制来获取,反射机制就要获得类或者类名称,那么就先获得符合要求的类,这里就要用到包扫描,我在前面的博客中有介绍过:【Java】包、jar包的扫描
首先是对类的注解:
@Component

1 @Retention(RetentionPolicy.RUNTIME) 2 @Target(ElementType.TYPE) 3 public @interface Component { 4     String id() default ""; 5 }

其中的id至关于类名称的别名,具备惟一性,若是不设置则不处理!经过这个注解咱们就能够判断哪一个类是须要进行操做的,就应该自动地为这个类生成一个对象和代理对象,将其添加到beanMap中,就是bean的标志!
若是说用过Spring的XML配置,这其实就至关于一个bean标签:

1 <bean id="XXX" class="XXX">
2  ...... 3 </bean>

注解中的id就至关于id属性,咱们是经过反射机制获得注解的,固然能获得类名称,那就至关于有了class属性!

可是仅仅有这个注解是彻底不够的,咱们只能经过反射机制产生一个对象,但它的成员都没赋值,仅仅是一具躯壳,因此就须要对成员添加注解,将咱们须要的值注入进来;固然也能够给方法添加注解,经过setter方法给成员赋值,Spring就是使用的这种方式!
这是对成员的注解:
@Autowired

1 @Retention(RetentionPolicy.RUNTIME) 2 @Target({ElementType.FIELD, ElementType.METHOD, ElementType.CONSTRUCTOR}) 3 public @interface Autowired { 4     boolean requisite() default true; 5 }

这里直接使用的spring源码,在源码中,这个注解能够成员、方法以及构造方法添加。其中的requisite是是否必须注入,这是Spring提供的更为细腻的操做,个人实现暂时不考虑它。

若是说这个注解是给成员添加的,那么标志着它须要赋值!使用这个注解的前提是它自己是一个复杂类型,不是基本类型,它的赋值,是将咱们beanMap中的符合要求的Bean注入进去!至于基本类型后面有别的解决办法。
用Component 和Autowired注解其实就至关于以下XML的配置:

1 <bean id="XXX" class="XXX">
2     <property name="XXX" ref="XXX">
3 </bean>

咱们一样是经过反射机制获得的Autowired注解,那么必定能够获得成员名称,和成员类型,成员名称就至关于name属性,经过成员类型就能够获得类型名称,就至关于ref属性!

若是说是给构造方法添加,那么就规定了咱们在反射机制执行时须要调用哪一个构造方法,至关于以下:

1 <bean id="XXX" class="XXX">
2     <constructor-arg index="0" ref="XXX">
3     <constructor-arg index="1" ref="XXX">
4 </bean>

对于构造方法的处理我以为使用注解的方式比XML配置要更好,注解能够直接定位到某一个构造方法,可是XML文件的方式就须要遍历比较,找出符合要求的,并且关于这个符合要求这一说还有更为复杂的问题,我会在后面用XML的方式详细介绍!

还有一种就是对方法添加,实际上就是提供给setter方法使用的,经过执行setter方法给成员赋值,可能看到这里会以为这样作是否是画蛇添足,其实不是,由于这样作会避免我后面会谈到的循环依赖的问题!因此给方法添加,和对成员添加等效:

1 <bean id="XXX" class="XXX">
2     <property name="XXX" ref="XXX">
3 </bean>


上面我说过使用Autowired 是不处理基本类型的,它是将bean注入的,基本类型彻底没有必要做为bean,那么,咱们就能够给出一个注解,直接赋值:

@Value

1 @Retention(RetentionPolicy.RUNTIME) 2 @Target({ElementType.FIELD, ElementType.PARAMETER}) 3 public @interface Value { 4  String value(); 5 }

其中value就是咱们要注入的值,可是它是String类型的,可能须要强制类型转换
演示以下:

 1 @Component  2 public class TestA {  3  @Autowired  4     private TestB testB;  5     @Value(value="直接赋值")  6     private String member;  7     
 8     public TestA() {  9  } 10 
11 } 12 
13 @Component(id = "testB") 14 public class TestB { 15     private int a; 16     private TestA testA; 17     
18  @Autowired 19     public TestB(@Value(value="10")int a, TestA testA) { 20         this.a = a; 21         this.testA = testA; 22  } 23     
24 }

就至关于:

1 <bean class="xxx.xxx.TestA">
2     <property name="testB" ref="xxx.xxx.TestB">
3     <property name="member" value="直接赋值">
4 </bean>
5 <bean id="testB" class="xxx.xxx.TestB">
6     <constructor-arg index="0" value="10"></constructor-arg>
7     <constructor-arg index="1" ref="xxx.xxx.TestA"></constructor-arg>
8 </bean>

为了简单处理,Autowired注解我在后面就只处理成员的。

有了上面的两个注解是否够呢?固然不够。仔细想想,若是说咱们须要Spring帮咱们建立的对象,其对应的类又被打成了jar包,那么咱们彻底没有办法对已经造成jar包的代码添加注解;又或者说是咱们须要建立的对象不是经过反射机制就能产生的,它是一个工厂对象,须要走工厂模式那一套来建立,上面的两个注解就远远不能知足咱们的要求了!所以,咱们还须要一个做为补充的注解:

 

@Bean

1 @Retention(RetentionPolicy.RUNTIME) 2 @Target(ElementType.METHOD) 3 public @interface Bean { 4     String id() default ""; 5 }

能够看出这是对方法的注解,由于咱们能够经过反射机制执行方法,将方法的返回值做为Bean的原始对象,再产生一个代理对象,这样就能解决上面的所说的问题!

 1 @Component  2 public class Action {  3     
 4     @Bean(id="getDocumentBuilderFactory")  5     public DocumentBuilderFactory getDocumnet() throws Exception {  6         return DocumentBuilderFactory.newInstance();  7  }  8     
 9  @Bean 10     public DocumentBuilder getDocumentBuilder(DocumentBuilderFactory factory) throws Exception { 11         return factory.newDocumentBuilder(); 12  } 13     
14 }

就至关于:

1 <bean class="xxx.xxx.Action "></bean>
2 <bean class="javax.xml.parsers.DocumentBuilderFactory" id="getDocumentBuilderFactory" 
3  factory-method="newInstance"></bean>
4 <bean class="javax.xml.parsers.DocumentBuilderFactory" 
5  factory-bean="getDocumentBuilderFactory" factory-method="newDocumentBuilder">
6 </bean>

有了这些注解,咱们就能对包进行扫描,能够继续向下进行!

AnnotationContext:
这个类继承自AbstractApplicationContext,它是protected的,不对外提供,我用它来进行有关注解的扫描和解析,但它的功能有限,不能完成所有的注入,这会涉及到注入的顺序,以及注入之间的依赖关系:

 1 /**
 2  * 执行包扫描  3  * 将符合要求的结果添加到父类AbstractApplicationContext的beanMap中  4  * 只处理@Component和@Bean注解  5  * @Autowired注解留给下一级处理  6  */
 7 public class AnnotationContext extends AbstractApplicationContext {  8     // method缓冲区,保存暂时不能执行的方法,其中的MethodBuffer用来封装method,以及invoke时所须要的内容
 9     private List<MethodBuffer> methodList;  10 
 11     protected AnnotationContext() {  12  }  13     
 14     protected AnnotationContext(String packageName) {  15  scanPackage(packageName);  16  }  17     
 18     /**
 19  * 经过aopFactory产生代理对象,将代理对象和原始对象封装成bean添加到父类的map中  20      */
 21     private void addBean(Class<?> klass, Object object, String id, String className) {  22         // aopFactory是其父类AbstractApplicationContext的成员,原来产生代理对象
 23         Object proxy = aopFactory.creatCGLibProxy(klass, object);  24         // AnnoationBean是BeanElement接口的一个实现类
 25         AnnotationBean bean = new AnnotationBean(object, proxy);  26         // 父类AbstractApplicationContext的add方法
 27  add(id, className, bean);  28  }  29     
 30     protected void scanPackage(String packageName) {  31         new PackageScanner() {  32  @Override  33             public void dealClass(Class<?> klass) {  34                 if (!klass.isAnnotationPresent(Component.class)) return;  35                 Component component = klass.getAnnotation(Component.class);  36                 String className = klass.getName();  37                 String name = component.id();  38                 try {  39                     // 这里简单起见,不考虑构造方法的重载,默认执行无参构造 
 40                     Object object = klass.newInstance();  41                     // 产生BeanElement,加入到beanMap中
 42  addBean(klass, object, name, className);  43                     // 处理带有@Bean注解的方法
 44  dealMethod(klass, object);  45                 } catch (Exception e) {  46                     // TODO 
 47  e.printStackTrace();  48  }  49  }  50  }.scanPackage(packageName);  51         if (methodList == null) return;  52         // 执行缓存的全部方法
 53         for (MethodBuffer methodBuffer : methodList) {  54             // 得到方法执行所须要的东西
 55             String id = methodBuffer.getId();  56             Class<?> returnClass = methodBuffer.getReturnClass();  57             Method method = methodBuffer.getMethod();  58             Object object = methodBuffer.getObject();  59             Parameter[] parameters = methodBuffer.getParameters();  60             
 61             try {  62  dealMultiParaMethod(returnClass, method, object, parameters, id);  63             } catch (Exception e) {  64                 // TODO 
 65  e.printStackTrace();  66  }  67  }  68  methodList.clear();  69  }  70     
 71     private void dealMultiParaMethod(Class<?> returnClass, Method method,  72  Object object, Parameter[] parameters, String id)  73                     throws BeansException, IllegalAccessException, IllegalArgumentException,  74  InvocationTargetException, ValueOnlyPrimitiveType {  75         int count = parameters.length;  76         Object[] result = new Object[count];  77         
 78         for (int index = 0; index < count; index++) {  79             Parameter para = parameters[index];  80             // 判断参数是否带有@Value注解
 81             if (para.isAnnotationPresent(Value.class)) {  82                 Class<?> type = para.getType();  83                 // 判断@Value注解标识的参数是不是基本类型(八大类型和String)
 84                 if (!type.isPrimitive() && !type.equals(String.class)) {  85                     throw new ValueOnlyPrimitiveType("Value只能用基本类型!");  86  }  87                 // TypeConversion是我本身的一个工具类,用于将字符串转换成基本类型!
 88                 result[index] = TypeConversion.getValue(para.getAnnotation(Value.class).value(),  89  para.getType().getSimpleName());  90             } else {  91                 // 若是不是基本类型,那么就须要从beanMap中获取符合要求的bean
 92                 result[index] = getBean(para.getType());  93  }  94  }  95         // 执行方法,得到方法返回值
 96         Object returnObject = method.invoke(object, result);  97         // 为方法执行结果建立bean,添加到beanMap中
 98  addBean(returnClass, returnObject , id, returnClass.getName());  99  } 100     
101     /**
102  * 遍历全部方法,处理带有@Bean注解的方法 103      */
104     private void dealMethod(Class<?> klass, Object object) throws IllegalAccessException, IllegalArgumentException, InvocationTargetException { 105         Method[] methods = klass.getDeclaredMethods(); 106         for (Method method : methods) { 107             if (!method.isAnnotationPresent(Bean.class)) continue; 108             
109             Class<?> returnType = method.getReturnType(); 110             if (returnType.equals(void.class)) { 111                 // TODO 若是没有返回值,那么根本没有必要作
112                 return; 113  } 114             String id= method.getAnnotation(Bean.class).id(); 115             Parameter[] parameters = method.getParameters(); 116             // 判断方法是否有参数,没有参数,直接执行,添加Bean 117             // 有参数就先缓存起来,等全部都扫描完成后再执行
118             if (parameters.length <= 0) { 119                 Object returnObject = method.invoke(object); 120  addBean(returnType, returnObject, id, returnType.getName()); 121             } else { 122                 (methodList = methodList == null ? new ArrayList<>() : methodList) 123                     .add(new MethodBuffer(returnType, object, method, parameters, id)); 124  } 125  } 126  } 127     
128 }

这个类只负责扫描包,为带有@Component注解的类经过反射机制生成对象,再经过代理工厂将其加工成代理对象,而后封装再AnnotationBean中做为bean,将其添加到BeanMap中!
其次还处理了带有@Bean注解的的方法,若是说是方法带有参数,那么就像将这个方法的执行延后,等全部东西都扫描完成后再执行;而对于无参的方法,则能够直接执行,并为执行结果产生的对象建立代理,生成AnnotationBean,添加进beanMap中。至于@Autowired注解这个类暂不处理,留给下一级处理!


AnnotationBean类的定义以下:

 1 /**
 2  * 注解分支中BeanElement的具体实现类  3  */
 4 public class AnnotationBean implements BeanElement {  5     private boolean DI; // 判断是否完成注入
 6     private Object object; // 原始对象
 7     private Object proxy; // 代理对象
 8     
 9  AnnotationBean() { 10         this(false, null, null); 11  } 12     
13  AnnotationBean(Object object, Object proxy) { 14         this(false, object, proxy); 15  } 16     
17     AnnotationBean(boolean dI, Object object, Object proxy) { 18         DI = dI; 19  setObject(object); 20  setProxy(proxy); 21  } 22     
23  @Override 24     public Object getObject() { 25         return object; 26  } 27     
28  AnnotationBean setObject(Object object) { 29         this.object = object; 30         return this; 31  } 32 
33  AnnotationBean setProxy(Object proxy) { 34         this.proxy = proxy; 35          return this; 36  } 37 
38     void setDI(boolean DI) { 39         this.DI = DI; 40  } 41     
42  @Override 43     public boolean isDI() { 44         return DI; 45  } 46 
47  @Override 48     @SuppressWarnings("unchecked") 49     public <E> E getProxy() { 50         return (E) proxy; 51  } 52     
53 }

MethodBuffer 类以下:

 1 /**
 2  * 带有@Bean注解的方法封装类  3  */
 4 public class MethodBuffer {  5     private String id; // bean的id
 6     private Class<?> returnType; // 方法返回值类型
 7     private Object object; // 方法执行所需对象
 8     private Method method; // 方法自己
 9     private Parameter[] parameters; // 方法所需参数
10     
11  MethodBuffer() { 12  } 13 
14     MethodBuffer(Class<?> returnType, Object object, Method method, Parameter[] parameters, String id) { 15         this.returnType = returnType; 16         this.object = object; 17         this.method = method; 18         this.parameters = parameters; 19         this.id = id; 20  } 21 
22  String getId() { 23         return id; 24  } 25     
26  Object getObject() { 27         return object; 28  } 29 
30     Class<?> getReturnType() { 31         return returnType; 32  } 33 
34  Method getMethod() { 35         return method; 36  } 37 
38  Parameter[] getParameters() { 39         return parameters; 40  } 41     
42 }

*在处理@Bean注解时,就能发现我前面提出的问题,用CGLibProxy产生的代理为何还须要原始对象?
咱们处理@Bean注解,是为了获得方法的返回值,若是直接对返回值所对应的类进行代理,产生代理对象,那么,在方法执行时,若是原始对象的成员被赋值了,那么代理对象是不会知道的,那么产生的代理是不完整的!使用methodProxy.invokeSuper(proxyObjet, args)方法是不可行的了!因此必定要保存原始对象,使用method.invoke(object, args)才是合理的!

AnnotationConfigApplicationContext:
这是注解这一支最高级的容器,是最终留给用户使用的,用来完成最后@Autowired注解标识的成员的注入!
若是说是须要注入的bean都能找的到,且这些bean都完成了注入,那么其注入过程会很是简单,但如果,彼此之间的依赖关系比较复杂,你中有我,我中有你,会造成一个环形闭环,陷入死循环,这就是循环依赖!


循环依赖

 

这里有四个类ClassA、ClassB、ClassC、ClassD,而且都没有完成注入,若是如今想getBean获得ClassA的Bean,那么就须要先对ClassA的Bean完成注入,可是其注入又须要ClassB,那么,就须要先将B注入,但B又要C,那就先注入C,但是C须要D,只能先注入D,可是D确须要A!绕了一圈又回来了,陷入了死循环,这就是咱们要解决的循环依赖!


解决方案:
1、前面我说过@Autowired注解能够给setter方法添加,用来解决循环依赖!
若是说咱们使用这种方式给ClassA的setClassB方法添加@Autowired,而不是给其ClassB成员添加,那么这个循环天然而然就不会出现!
2、假设自身以完成注入:
在ClassA注入以前,让它的状态变为完成注入,而后继续找B,发现B没注入,找C,C没注入,找D,D没注入,找A,此时A的状态是完成注入,天然也就不会产生闭环!

因此AnnotationConfigApplicationContext就是为了最后的注入:

 1 public class AnnotationConfigApplicationContext extends AnnotationContext {  2     public AnnotationConfigApplicationContext() {  3  }  4     // 调用父类的构造
 5     public AnnotationConfigApplicationContext(String packageName) {  6         super(packageName);  7  }  8     // Advice是代理的拦截处理,内部使用默认的一种方式,用户也能够注入一种方式
 9     public AnnotationConfigApplicationContext setAdvice(Advice advice) { 10  aopFactory.setAdvice(advice); 11         return this; 12  } 13     
14     public AnnotationConfigApplicationContext parsePackage(String packageName) { 15  scanPackage(packageName); 16         return this; 17  } 18     
19  @Override 20     public Object getBean(String name) throws BeansException { 21         String className = beanNameMap.get(name); 22         return className == null ? get(name) : get(className); 23  } 24 
25     private <T> T get(String className, Class<?> klass) throws BeansException { 26         BeanElement bean = beanMap.get(className); 27         if (bean == null) { 28             throw new BeansException("Bean :" + klass + "不存在!"); 29  } 30         if (!bean.isDI() && bean instanceof AnnotationBean) { 31  autowired(klass, (AnnotationBean)bean); 32  } 33         return bean.getProxy(); 34  } 35     
36  @Override 37     public <T> T getBean(Class<T> klass) throws BeansException { 38         return get(klass.getName()); 39  } 40     
41     private void autowired(AnnotationBean bean) throws BeansException { 42         // 一开始令自身完成注入
43         bean.setDI(true); 44         Object object = bean.getObject(); 45         Class<?> klass = object.getClass(); 46         Field[] fields = klass.getDeclaredFields(); 47         Object arg = null; 48         for (Field field : fields) { 49             if (field.isAnnotationPresent(Value.class)) { 50                 try { 51                     // 注入基本类型的值
52                     arg = injectValue(field); 53                 } catch (ValueOnlyPrimitiveType e) { 54  e.printStackTrace(); 55  } 56             } else if (field.isAnnotationPresent(Autowired.class)) { 57                 // 注入bean中的Bean
58                 arg = injectBean(field); 59             } else { 60                 continue; 61  } 62             try { 63                 // 成员注入
64                 field.setAccessible(true); 65  field.set(object, arg); 66             } catch (Exception e) { 67                 throw new BeansException(klass + "依赖关系不正确!"); 68  } 69  } 70  } 71     
72     private Object injectValue(Field field) throws ValueOnlyPrimitiveType { 73         Class<?> type = field.getType(); 74         if (!type.isPrimitive() && !type.equals(String.class)) { 75             throw new ValueOnlyPrimitiveType("Value只能用于八大基本类型!"); 76  } 77         Value value = field.getAnnotation(Value.class); 78         return TypeConversion.getValue(value.value(), type.getSimpleName()); 79  } 80     
81     private Object injectBean(Field field) throws BeansException { 82         Class<?> fieldType = field.getType(); 83         BeanElement fieldBean = beanMap.get(fieldType.getName()); 84         if (fieldBean == null) { return null;} 85         if (!fieldBean.isDI() && fieldBean instanceof AnnotationBean) { 86  autowired((AnnotationBean)fieldBean); 87  } 88         return fieldBean.getProxy(); 89  } 90 }

这里解决循环依赖就使用了我上面给出的第二种方案,利用递归来实现!

注解部分的简单实现已基本完成,虽然有些地方没有处理或是处理的比较简陋,可是SpringIOC的核心思想就是如此,只不过Spring实现的更为精致、细腻!
来看看它的使用:
先给出几个须要注入的类:

 1 @Component(id="studentA")  2 public class StudentA {  3     @Value(value="我是A")  4  String name;  5  @Autowired  6     private StudentB B;  7     
 8     public StudentA() {  9  } 10     
11  @Override 12     public String toString() { 13         return "A:" + name + "->" + B; 14  } 15     
16 } 17 
18 @Component 19 public class StudentB { 20     @Value(value="我是B") 21     private String name; 22  @Autowired 23     private StudentC C; 24     
25     public StudentB() { 26  } 27 
28  @Override 29     public String toString() { 30         return "B:" + name + "->" + C; 31  } 32     
33 } 34 
35 @Component 36 public class StudentC { 37     @Value(value="我是C") 38     private String name; 39     
40  @Autowired 41     private StudentA A; 42     
43     public StudentC() { 44  } 45 
46  @Override 47     public String toString() { 48         return "C:" + name; 49  } 50     
51 } 52 
53 public class StudentD { 54     private String name; 55  @Autowired 56     private StudentA A; 57     
58     public StudentD(String name) { 59         this.name = name; 60  } 61 
62  @Override 63     public String toString() { 64         return "D:" + name + "->" + A; 65  } 66     
67 } 68 
69 @Component 70 public class MethodAction { 71     public MethodAction() { 72  } 73 
74     @Bean(id="studentD") 75     public StudentD getStudentD(@Value(value="我是D")String name) { 76         return new StudentD(name); 77  } 78 }

主函数:

1 public static void main(String[] args) throws BeansException { 2     ApplicationContext applicationContext = 
3                 new AnnotationConfigApplicationContext("com.zc.ioc.demo"); 4         StudentD studentD = applicationContext.getBean(StudentD.class); 5  System.out.println(studentD); 6 
7 }

结果是:

或者这样使用:

1 public static void main(String[] args) throws BeansException { 2     BeanFactory beanFactory = new AnnotationConfigApplicationContext("com.zc.ioc.demo"); 3         StudentD studentD = (StudentD) beanFactory.getBean("studentD"); 4  System.out.println(studentD); 5 }

结果:

有关XML方式以及AOP的实现我会在下一篇给出。

相关文章
相关标签/搜索