IoC和AOP是spring的核心,可以说没有他们就没有庞大的Spring家族。我也是心血来潮,自己动手写了一个简易的Spring框架。可以通过使用注解来实现IoC容器和AOP。
先说IoC部分吧。源码下载:download.csdn.net/detail/jobs…
IoC
先定义了两个注解@MyBean和@MyAutowired,用来标记Bean和自动注入的对象。
- 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();
- }
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();
}
- package mySpring.autowired;
- import java.lang.annotation.*;
- @Target({ElementType.FIELD, ElementType.METHOD})
- @Retention(RetentionPolicy.RUNTIME)
- @Inherited
- @Documented
- public @interface MyAutowired {
- }
package mySpring.autowired;
import java.lang.annotation.*;
@Target({ElementType.FIELD, ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Documented
public @interface MyAutowired {
}
实现思路:
我的思路是在一个properties文件里配置要扫描的包(Resource定位),通过扫描这些包获得他们的Class对象存入List中(载入和解析),将list中的Class对象转储到Map中,以@Bean里配置的Bean名为key(注册),再通过反射将Map里的Class转换成Bean(注入)。当然,注入的时候要判断是否循环依赖,这个我是在注入过程中判断的,也可以预判,但可能会稍麻烦些。下面是自动注入类的代码:
- 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 classes:list) {
- //注册
- Map<String, Object> judgeMap = new HashMap();
- //注入
- injection(mmp,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);
- String beanName= myBean.value(); //获得bean名称
- if(null==judgeMap.get(beanName))
- judgeMap.put(beanName,true);
- else { //又返回依赖他
- throw new Exception( "循环依赖");
- }
- if(null==mmp.get(beanName)) { //还没有被注入
- Object beanObj=classes.newInstance(); //获得bean实例
- 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);
- if(fieldClass.isAnnotationPresent(MyBean. class)) {//该属性依赖其它Bean
- MyBean tbean = (MyBean) fieldClass.getAnnotation(MyBean.class);
- injection(mmp,fieldClass,judgeMap);
- field.set(beanObj, mmp.get(tbean.value()));
- }
- else { //该属性不依赖其它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);
- //强制设置值 破坏了封装性
- field.setAccessible(true);
- if(fieldClass.isAnnotationPresent(MyBean.class)) { //该属性依赖其它Bean
- MyBean tbean = (MyBean) fieldClass.getAnnotation(MyBean.class);
- field.set(obj, mmp.get(tbean.value()));
- }else { //该属性不依赖其它Bean
- Object object=fieldClass.newInstance();
- field.set(obj, object);
- }
- }
- }
- }
- }
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 classes:list) {
//注册
Map<String, Object> judgeMap = new HashMap();
//注入
injection(mmp,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);
String beanName= myBean.value(); //获得bean名称
if(null==judgeMap.get(beanName))
judgeMap.put(beanName,true);
else { //又返回依赖他
throw new Exception("循环依赖");
}
if(null==mmp.get(beanName)) { //还没有被注入
Object beanObj=classes.newInstance(); //获得bean实例
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);
if(fieldClass.isAnnotationPresent(MyBean.class)) {//该属性依赖其它Bean
MyBean tbean = (MyBean) fieldClass.getAnnotation(MyBean.class);
injection(mmp,fieldClass,judgeMap);
field.set(beanObj, mmp.get(tbean.value()));
}
else { //该属性不依赖其它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);
//强制设置值 破坏了封装性
field.setAccessible(true);
if(fieldClass.isAnnotationPresent(MyBean.class)) {//该属性依赖其它Bean
MyBean tbean = (MyBean) fieldClass.getAnnotation(MyBean.class);
field.set(obj, mmp.get(tbean.value()));
}else { //该属性不依赖其它Bean
Object object=fieldClass.newInstance();
field.set(obj, object);
}
}
}
}
}
接下来说AOP。
AOP
AOP我是选择用CGLIB实现的。先是定义了两个注解。@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();
- }
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();
}
- 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 {
- }
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 {
}
我只实现了三种通知,Before,After,Surround(前面两种结合,Spring里没有这种。。)。为每种通知定义一个接口,每个接口都继承Advice(空接口)。
实现原理:
AOP是在完成上述IoC注入后再实现的。就是为每个Bean生成一个代理类,根据注解信息提供相应的方法拦截操作。Spring的AOP是会形成一条拦截器链的,我没有做得那么复杂。我写了一个控制类来进行切面信息判断来实现正确的拦截(替代拦截器链),这个控制器会根据注解选择正确的操作执行。我将操作也独立成了一个类,进行解耦。
下面是控制类:
- 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, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
- //有忽视注解
- if(method.isAnnotationPresent(Ignore.class))
- return methodProxy.invokeSuper(o, objects);
- //没有切入点
- 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 methodProxy, Advice advice) throws Throwable {
- //有忽视注解
- if(method.isAnnotationPresent(Ignore.class))
- return methodProxy.invokeSuper(o, objects);
- //有切入点
- if(method.isAnnotationPresent(PointCut.class)) {
- Advice advice2=getAdvice(method);
- return doAdvice(o,objects,methodProxy,advice2);
- } else { //没有切入点
- 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;
- }
- }
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, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
//有忽视注解
if(method.isAnnotationPresent(Ignore.class))
return methodProxy.invokeSuper(o, objects);
//没有切入点
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 methodProxy, Advice advice) throws Throwable {
//有忽视注解
if(method.isAnnotationPresent(Ignore.class))
return methodProxy.invokeSuper(o, objects);
//有切入点
if(method.isAnnotationPresent(PointCut.class)) {
Advice advice2=getAdvice(method);
return doAdvice(o,objects,methodProxy,advice2);
} else { //没有切入点
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;
}
}
下面是具体操作执行类
- 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;
- }
- }
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;
}
}
执行完AOP后,我们要重新进行一遍注入,这就是上面那个自动注入类的reinjection方法要做的事。
启动Spring也非常简单,只要通过Class.forName("mySpring.autowired.BeanFactory");加载类就行。当然这么做有一个坏处就是减少了灵活性,配置文件必须按照严格规范。
下面是BeanFactory类:
- 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";
- //初始化IoC容器
- 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);
- }
- }
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";
//初始化IoC容器
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);
}
}
献丑了,但也算了了自己写一个简易Spring的心愿,很多地方有待改进。望大牛指出。
对了,写的时候遇到一个问题,那就是CGLIB生成的子类无法获取到它父类的属性,也因为这个瞎忙活了很久,希望有人能为我解答。
上面的问题已得到解答: