IoC and AOP are at the heart of Spring, and without them there would be no large Spring family. On a whim, I wrote a simple Spring framework myself. The IoC container and AOP can be implemented using annotations.

Let’s start with the IoC part. The source code download: download.csdn.net/detail/jobs…

IoC

Two annotations, @myBean and @MyAutoWired, are defined to mark the Bean and the auto-injected object.

package mySpring.autowired;

import java.lang.annotation.*;

/**
 * Created by 10033 on 2017/5/9.
 */
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyBean {
    String value();
}Copy the code
[java]
view plain
copy


print
?

  1. package mySpring.autowired;  
  2.   
  3. import java.lang.annotation.*;  
  4.   
  5. @Target({ElementType.FIELD,  ElementType.METHOD})  
  6. @Retention(RetentionPolicy.RUNTIME)  
  7. @Inherited    
  8. @Documented   
  9. public @interface MyAutowired {  
  10. }  
package mySpring.autowired;

import java.lang.annotation.*;

@Target({ElementType.FIELD,  ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited  
@Documented 
public @interface MyAutowired {
}
Copy the code

Implementation idea:

The idea is to configure the package to scan in a Properties file (
The Resource location) by scanning these packages to get their Class objects into the List (
Load and parse), dump the Class object from list to Map, using the Bean named key configured in @bean (
registered), and use reflection to convert the Class in the Map into beans (
injection). Of course, it is necessary to determine whether circular dependencies are generated during injection, which I did in the process of injection and can also be predicted, but it may be a bit more troublesome.

Here is the code for the auto-injection class:

[java]
view plain
copy


print
?

  1. package mySpring.autowired;  
  2.   
  3. / * * 
  4.  * Created by 10033 on 2017/5/9. 
  5. * /  
  6.   
  7. import java.io.IOException;  
  8. import java.lang.reflect.Field;  
  9. import java.util.HashMap;  
  10. import java.util.List;  
  11. import java.util.Map;  
  12.   
  13. / * * 
  14. * Automatic injection of classes 
  15. * /  
  16. public class AutomaticInjection {  
  17.   
  18.     public static void automaticInjection(String key, Map mmp) {  
  19.         try {  
  20.             List<Class> list = GetClass.getClassList(key);  
  21.   
  22.             for(Class classes:list) {  
  23.                 / / register  
  24.                 Map<String, Object> judgeMap = new HashMap();  
  25.                 / / injection  
  26.                 injection(mmp,classes,judgeMap);  
  27.             }  
  28.         } catch (IOException e) {  
  29.             e.printStackTrace();  
  30.         } catch (ClassNotFoundException e) {  
  31.             e.printStackTrace();  
  32.         } catch (Exception e) {  
  33.             e.printStackTrace();  
  34.         }  
  35.     }  
  36.   
  37.     // Inject and determine whether cyclic dependencies exist  
  38.     private static void injection(Map mmp, Class classes, Map judgeMap)  
  39.             throws Exception {  
  40.         boolean isExist = classes.isAnnotationPresent(MyBean.class);  
  41.         // If the annotation exists  
  42.         if(isExist) {  
  43.             MyBean myBean = (MyBean) classes.getAnnotation(MyBean.class);  
  44.             String beanName= myBean.value(); // Get the bean name  
  45.             if(null==judgeMap.get(beanName))  
  46.                 judgeMap.put(beanName,true);  
  47.             else { // Go back to relying on him  
  48.                 throw new Exception( “Cyclic dependency”);  
  49.             }  
  50.   
  51.             if(null==mmp.get(beanName)) { // Not yet injected  
  52.                 Object beanObj=classes.newInstance(); // Get the bean instance  
  53.   
  54.                 Field[] fields=classes.getDeclaredFields();  
  55.                 boolean fieldExist;  
  56.                 for(Field field:fields) {  
  57.                     fieldExist=field.isAnnotationPresent(MyAutowired.class);  
  58.   
  59.                     if(fieldExist) {  
  60.                         String classtype=field.getGenericType().toString();  
  61.                         Class fieldClass=Class.forName(classtype.substring(6));  
  62.   
  63.                         // Forcing a value breaks encapsulation  
  64.                         field.setAccessible(true);  
  65.   
  66.                         if(fieldClass.isAnnotationPresent(MyBean. class)) {// This property depends on other beans  
  67.                             MyBean tbean = (MyBean) fieldClass.getAnnotation(MyBean.class);  
  68.                             injection(mmp,fieldClass,judgeMap);  
  69.                             field.set(beanObj, mmp.get(tbean.value()));  
  70.   
  71.                         }  
  72.   
  73.                         else {  // This property does not depend on other beans  
  74.                             Object object=fieldClass.newInstance();  
  75.                             field.set(beanObj, object);  
  76.                         }  
  77.                     }  
  78.                 }  
  79.                 mmp.put(beanName, beanObj);  
  80.             }  
  81.   
  82.         }  
  83.     }  
  84.   
  85.     public static void reinjection(Map mmp, Class classes, Object obj)  throws ClassNotFoundException, IllegalAccessException, InstantiationException {  
  86.         Field[] fields=classes.getDeclaredFields();  
  87.         boolean fieldExist;  
  88.         for(Field field:fields) {  
  89.             fieldExist=field.isAnnotationPresent(MyAutowired.class);  
  90.   
  91.             if(fieldExist) {  
  92.                 String classtype=field.getGenericType().toString();  
  93.                 Class fieldClass=Class.forName(classtype.substring(6));  
  94.                 field.setAccessible(true);  
  95.                 // Forcing a value breaks encapsulation  
  96.                 field.setAccessible(true);  
  97.   
  98.                 if(fieldClass.isAnnotationPresent(MyBean.class)) { // This property depends on other beans  
  99.                     MyBean tbean = (MyBean) fieldClass.getAnnotation(MyBean.class);  
  100.                     field.set(obj, mmp.get(tbean.value()));  
  101.   
  102.                 }else { // This property does not depend on other beans  
  103.                     Object object=fieldClass.newInstance();  
  104.                     field.set(obj, object);  
  105.                 }  
  106.             }  
  107.         }  
  108.     }  
  109.   
  110. }  
package mySpring.autowired; /** * Created by 10033 on 2017/5/9. */ import java.io.IOException; import java.lang.reflect.Field; import java.util.HashMap; import java.util.List; import java.util.Map; /** * public class AutomaticInjection {public static void AutomaticInjection (String key, Map mmp) { try { List<Class> list = GetClass.getClassList(key); For (Class :list) {// Register Map<String, Object> judgeMap = new HashMap(); / / injection injection (MMPS, classes, judgeMap); } } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (Exception e) { e.printStackTrace(); Private static void injection(Map MMP, Class classes); Map judgeMap) throws Exception { boolean isExist = classes.isAnnotationPresent(MyBean.class); If (isExist) {MyBean MyBean = (MyBean) classes.getannotation (mybean.class); // If (isExist) {MyBean MyBean = (MyBean) classes.getannotation (mybean.class); String beanName= myBean.value(); If (null== judgemap. get(beanName)) judgemap. put(beanName,true); Else {// throw new Exception(" loop dependency "); } if(null==mmp.get(beanName)) {// Object beanObj= classes.newinstance (); / / get the bean instance Field [] fields = classes. GetDeclaredFields (); boolean fieldExist; for(Field field:fields) { fieldExist=field.isAnnotationPresent(MyAutowired.class); if(fieldExist) { String classtype=field.getGenericType().toString(); Class fieldClass=Class.forName(classtype.substring(6)); // Forcing a value breaks the encapsulation field.setaccessible (true); If (fieldClass. IsAnnotationPresent (MyBean. Class)) {/ / this property depends on other Bean MyBean tbean = (MyBean) fieldClass.getAnnotation(MyBean.class); injection(mmp,fieldClass,judgeMap); field.set(beanObj, mmp.get(tbean.value())); } else {// This property does not depend on other Bean Object Object = fieldClass.newinstance (); field.set(beanObj, object); } } } mmp.put(beanName, beanObj); } } } public static void reinjection(Map mmp, Class classes, Object obj) throws ClassNotFoundException, IllegalAccessException, InstantiationException { Field[] fields=classes.getDeclaredFields(); boolean fieldExist; for(Field field:fields) { fieldExist=field.isAnnotationPresent(MyAutowired.class); if(fieldExist) { String classtype=field.getGenericType().toString(); Class fieldClass=Class.forName(classtype.substring(6)); field.setAccessible(true); // Forcing a value breaks the encapsulation field.setaccessible (true); If (fieldClass. IsAnnotationPresent (MyBean. Class)) {/ / this property depends on other Bean MyBean tbean = (MyBean) fieldClass.getAnnotation(MyBean.class); field.set(obj, mmp.get(tbean.value())); }else {// This property does not depend on other Bean Object Object = fieldClass.newinstance (); field.set(obj, object); } } } } }Copy the code

Next, AOP.

AOP

AOP I choose to use CGLIB implementation. First, two annotations are defined. The @pointcut, @ Ignore.

package mySpring.aop;

import java.lang.annotation.*;

/**
 * Created by 10033 on 2017/5/12.
 */
@Target({ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface PointCut {
    String value();
}
Copy the code
[java]
view plain
copy


print
?

  1. package mySpring.aop;  
  2.   
  3. import java.lang.annotation.*;  
  4.   
  5. / * * 
  6.  * Created by 10033 on 2017/5/12. 
  7. * /  
  8. @Target({ElementType.METHOD})  
  9. @Retention(RetentionPolicy.RUNTIME)  
  10. @Inherited  
  11. @Documented  
  12. public @interface Ignore {  
  13. }  
package mySpring.aop;

import java.lang.annotation.*;

/**
 * Created by 10033 on 2017/5/12.
 */
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface Ignore {
}
Copy the code


I only implemented three notifications: Before, After, Surround. . Define an interface for each notification, and each interface inherits Advice (empty interface).

Implementation principle:

AOP is implemented after the above IoC injection. This is to generate a proxy class for each Bean that provides method interception operations based on annotation information. Spring’s AOP will form a chain of interceptors, but I’m not going to go that far. I have written a control class that performs section information judgment to implement the correct interception (instead of interceptor chain). This controller will select the correct action to perform according to the annotations. I decoupled the operations into a class as well.

Here are the control classes:

[java]
view plain
copy


print
?

  1. package mySpring.aop;  
  2.   
  3. / * * 
  4.  * Created by 10033 on 2017/5/12. 
  5. * /  
  6.   
  7. import net.sf.cglib.proxy.MethodProxy;  
  8.   
  9. import java.lang.reflect.Method;  
  10.   
  11. / * * 
  12. * Use annotations to determine which notification to execute 
  13. * /  
  14. public class ProxyController {  
  15.   
  16.     // No class annotations  
  17.     public static Object doController  
  18.             (Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {  
  19.         // There are ignoring notes  
  20.         if(method.isAnnotationPresent(Ignore.class))  
  21.             return methodProxy.invokeSuper(o, objects);  
  22.         // There is no pointcut  
  23.         if(! method.isAnnotationPresent(PointCut.class)) {  
  24.             return methodProxy.invokeSuper(o, objects);  
  25.         }else { // There is an entry point  
  26.             Advice advice=getAdvice(method);  
  27.             return doAdvice(o,objects,methodProxy,advice);  
  28.         }  
  29.   
  30.     }  
  31.   
  32.     // There are class annotations  
  33.     public static Object doController  
  34.         (Object o, Method method, Object[] objects, MethodProxy methodProxy, Advice advice) throws Throwable {  
  35.         // There are ignoring notes  
  36.         if(method.isAnnotationPresent(Ignore.class))  
  37.             return methodProxy.invokeSuper(o, objects);  
  38.         // There is an entry point  
  39.         if(method.isAnnotationPresent(PointCut.class)) {  
  40.             Advice advice2=getAdvice(method);  
  41.             return doAdvice(o,objects,methodProxy,advice2);  
  42.         } else { // There is no pointcut  
  43.             return doAdvice(o,objects,methodProxy,advice);  
  44.         }  
  45.   
  46.     }  
  47.   
  48.     private static Object doAdvice(Object o, Object[] objects, MethodProxy methodProxy, Advice advice)  throws Throwable {  
  49.         if(advice instanceof AfterAdvice) {  
  50.             return Execute.executeAfter(o,objects,methodProxy, (AfterAdvice) advice);  
  51.         }else if(advice instanceof BeforeAdvice) {  
  52.             return Execute.executeBefore(o,objects,methodProxy, (BeforeAdvice) advice);  
  53.         }else if(advice instanceof SurroundAdvice) {  
  54.             return Execute.executeSurround(o,objects,methodProxy, (SurroundAdvice) advice);  
  55.         }  
  56.         return null;  
  57.     }  
  58.   
  59.     private static Advice getAdvice(Method method) throws ClassNotFoundException, IllegalAccessException, InstantiationException {  
  60.         String classPath=method.getAnnotation(PointCut.class).value();  
  61.         Advice advice= (Advice) Class.forName(classPath).newInstance();  
  62.         return advice;  
  63.     }  
  64. }  
package mySpring.aop; /** * Created by 10033 on 2017/5/12. */ import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method; Public class ProxyController {// Public static Object doController (Object o) public static Object doxyController (Object o) Method method, Object[] objects, MethodProxy MethodProxy) throws Throwable {/ / Ignore comments if (method. IsAnnotationPresent (Ignore. Class)) return methodProxy.invokeSuper(o, objects); // No pointcut if(! method.isAnnotationPresent(PointCut.class)) { return methodProxy.invokeSuper(o, objects); }else {// Advice Advice =getAdvice(method); return doAdvice(o,objects,methodProxy,advice); Public static Object doController (Object o, Method Method, Object[] objects, MethodProxy, Advice Advice) throws Throwable {/ / Ignore comments if (method. IsAnnotationPresent (Ignore. Class)) return methodProxy. InvokeSuper (o,  objects); / / have to start the if (method. IsAnnotationPresent (PointCut. Class)) {Advice advice2 = getAdvice (method); return doAdvice(o,objects,methodProxy,advice2); } else {/ / there is no point return doAdvice (o, objects, methodProxy, advice); } } private static Object doAdvice(Object o, Object[] objects, MethodProxy methodProxy, Advice advice) throws Throwable { if(advice instanceof AfterAdvice) { return Execute.executeAfter(o,objects,methodProxy,  (AfterAdvice) advice); }else if(advice instanceof BeforeAdvice) { return Execute.executeBefore(o,objects,methodProxy, (BeforeAdvice) advice); }else if(advice instanceof SurroundAdvice) { return Execute.executeSurround(o,objects,methodProxy, (SurroundAdvice) advice); } return null; } private static Advice getAdvice(Method method) throws ClassNotFoundException, IllegalAccessException, InstantiationException { String classPath=method.getAnnotation(PointCut.class).value(); Advice advice= (Advice) Class.forName(classPath).newInstance(); return advice; }}Copy the code

Below are the concrete action execution classes

[java]
view plain
copy


print
?

  1. package mySpring.aop;  
  2.   
  3. import net.sf.cglib.proxy.MethodProxy;  
  4.   
  5. / * * 
  6.  * Created by 10033 on 2017/5/12. 
  7. * Enforcement notice 
  8. * /  
  9. public class Execute {  
  10.     public static Object executeAfter  
  11.             (Object o, Object[] objects, MethodProxy methodProxy, AfterAdvice advice) throws Throwable {  
  12.         Object object=methodProxy.invokeSuper(o,objects);  
  13.         advice.after();  
  14.         return object;  
  15.     }  
  16.     public static Object executeBefore  
  17.             (Object o, Object[] objects, MethodProxy methodProxy, BeforeAdvice advice) throws Throwable {  
  18.         advice.before();  
  19.         Object object=methodProxy.invokeSuper(o,objects);  
  20.   
  21.         return object;  
  22.     }  
  23.     public static Object executeSurround  
  24.             (Object o, Object[] objects, MethodProxy methodProxy, SurroundAdvice advice) throws Throwable {  
  25.         advice.before();  
  26.         Object object=methodProxy.invokeSuper(o,objects);  
  27.         advice.after();  
  28.         return object;  
  29.     }  
  30. }  
package mySpring.aop; import net.sf.cglib.proxy.MethodProxy; /** * Created by 10033 on 2017/5/12. */ public class Execute {public static Object executeAfter (Object o, Object[] objects, MethodProxy methodProxy, AfterAdvice advice) throws Throwable { Object object=methodProxy.invokeSuper(o,objects); advice.after(); return object; } public static Object executeBefore (Object o, Object[] objects, MethodProxy methodProxy, BeforeAdvice advice) throws Throwable { advice.before(); Object object=methodProxy.invokeSuper(o,objects); return object; } public static Object executeSurround (Object o, Object[] objects, MethodProxy methodProxy, SurroundAdvice advice) throws Throwable { advice.before(); Object object=methodProxy.invokeSuper(o,objects); advice.after(); return object; }}Copy the code


After executing AOP, we need to do the injection again, which is what the reinjection method of the auto-injection class above does.

Start the Spring is also very simple, as long as by Class. Class.forname (” mySpring. Autowired. The BeanFactory “); Just load the class. The downside of this, of course, is that it reduces flexibility; configuration files must follow strict specifications.

Here is the BeanFactory class:

[java]
view plain
copy


print
?

  1. package mySpring.autowired;  
  2.   
  3.   
  4. import mySpring.aop.ProxyFactory;  
  5.   
  6. import java.util.HashMap;  
  7. import java.util.Map;  
  8.   
  9. / * * 
  10.  * Created by 10033 on 2017/5/9. 
  11. * /  
  12. public class BeanFactory {  
  13.     public static Map<String, Object> map=new HashMap();  
  14.     private static final String KEY=“scan.package”;  
  15.     // Initialize the IoC container  
  16.     static {  
  17.         AutomaticInjection.automaticInjection(KEY,map);  
  18.         ProxyFactory.makeProxyBean(map);  
  19.   
  20.         // Generate the proxy and re-inject it  
  21.         for(String key:map.keySet()) {  
  22.             Class c=map.get(key).getClass().getSuperclass();  
  23.             try {  
  24.                 AutomaticInjection.reinjection(map,c,map.get(key));  
  25.             } catch (Exception e) {  
  26.                 e.printStackTrace();  
  27.             }  
  28.         }  
  29.     }  
  30.     public static Object getBean(String name) {  
  31.         return map.get(name);  
  32.     }  
  33. }  
package mySpring.autowired; import mySpring.aop.ProxyFactory; import java.util.HashMap; import java.util.Map; /** * Created by 10033 on 2017/5/9. */ public class BeanFactory { public static Map<String, Object> map=new HashMap(); private static final String KEY="scan.package"; / / initialize the IoC container static {AutomaticInjection. AutomaticInjection (KEY, map); ProxyFactory.makeProxyBean(map); For (String key: map.keyset ()) {Class c=map.get(key).getClass().getSuperclass(); try { AutomaticInjection.reinjection(map,c,map.get(key)); } catch (Exception e) { e.printStackTrace(); } } } public static Object getBean(String name) { return map.get(name); }}Copy the code

I made a fool of myself, but I also calculated my wish to write a simple Spring. Many places need to be improved. Wang Daniu pointed out.

CGLIB’s subclass can’t get the attributes of its parent class. It took a long time to do that.

The above questions have been answered: