【java】Spring AOP IOC 初探及实现
最近学习了AOP和IOC,了解并自己实现了Spring中的AOP和IOC
什么是AOP?
AOP即面向切面编程,能够让我们在不影响原有功能的情况下,对程序进行横向扩展,面向切面?横向扩展?第一次接触这两个词的时候我也是一脸懵逼。
说说我的理解:如果现有某个类的某个方法是已经封装好的,现在我们需要在执行这个方法的时候加点自己的东西,对原方法的执行进行干预。当然要求是不能破坏原类。这时需要AOP思想,把这个方法,即切点扩展成一个面来进行操作。(生成该类的代理,对代理进行操作)
例如:给这个方法加日志,执行方法前进行拦截等。
在上一篇博客中有讲到并手写实现,这里就不多赘述了。>>传送门<<
今天的目的就是结合AOP IOC
什么是IOC DI?
说的高大上就是“依赖注入”“控制反转”。假如现在A类中调用B类的方法,即A依赖B。传统做法:先new一个B,再调用方法。这是需要我们人为主动的去实现,而IOC的作用就是当我们调用需要B的A方法的时候,自动帮我们new出一个B,并将其注入A。
所以说这时候的对象已经的控制权在IOC容器,而不是靠我们程序员主动控制。
看到过一个有趣的例子:
我们可以把IOC当做一个婚介所。我现在要找女朋友,我只需要将我的要求告诉IOC这个婚介所,由婚介所在他管理的一堆资料中帮我找到符合我标准的对象,整个过程不需要我们控制,我们只需要和她谈恋爱就好!当然,找不到,婚介所就会通知我们(抛出异常)
同样,如果我们把主动控制当做自己去炒一盘土豆丝:我们要先准备土豆并切成丝,再热油,再把干辣椒花椒炒香,接着下土豆丝,各种调料,出锅,开吃!而,IOC就相当于饭店,你只需要说:“老板!来盘土豆丝!”(当然前提是我告诉老板我要吃的土豆丝该怎么做)就可以了!
自己的实现思路:
通过包扫描扫描出带有我注解的方法利用反射机制生成其代理并“存储”之。待我要求的对象再将其依赖的对象注入。在实现的过程中遇到了许许多多的问题。例如:如何处理循环依赖?解决扫描到带参方法时参数还没被扫描到的问题?
话不多说,上图!
比起前一篇,这次在实现的时候自己有了一些变动:这次咱们不用手工来累死累活来的手动添加***了,咱们来动态加入***!
InterceptorScanner用来包扫描动态添加***,设置Map
FyProxy将代理对象和原对象联系起来 (嘿嘿,这里的是否已经注入是来解决循环依赖问题的)
ProxyFactory产生代理(CGLIB或JDK方式)
ProxyBeanFactory联系类名和fyProxy
BeanFactory包扫描,根据注解自动添加proxyBeanFactory中的Map
这是***模块,InterceptorFactory中存放了 3个Map,图很清楚的反映了每一个目标方法,都有以一个***链。
好了,现在我也不知道要说啥了,咱看代码说话吧:
FyProxy
private Object proxy; // 代理对象
private Object object; // 原对象
private boolean injection; // 是否已经注入
public FyProxy() { // 构造方法
injection = false; // 没有注入
}
get和set方法就不说了
// 这是代理对象执行方法时会调用的前置***
// 根据传递过来的类和方法从InterceptorFactory中找到前置***链
// 遍历***链,实现方法,返回result
public boolean doBefore(Class<?> klass, Method method, Object[] args) {
List<InterceptorMethodDefination> list =
InterceptorFactory.getBeforeInterceptorList(new InterceptorTargetDefination(klass, method));
if (list == null) {
return true;
}
for (InterceptorMethodDefination interceptor : list) {
Method interceptorMethod = interceptor.getMethod();
Object interceptorObject = interceptor.getObject();
boolean result = false;
try {
result = (Boolean) interceptorMethod.invoke(interceptorObject,args);
} catch (Exception e) {
e.printStackTrace();
}
if (result == false) {
return false;
}
}
return true;
}
另外该类中还包含doAfter和doException,思路同上,只有传参有稍许不同,也就不多说了。
既然涉及到了InterceptorMethodDefination(***方法) 和 InterceptorTargetDefination(被拦截的目标), 那就先说说他俩吧。
InterceptorTargetDefination(被拦截的目标)
private Class<?> klass;
private Method method;
public InterceptorTargetDefination(Class<?> klass, Method method) {
super();
this.klass = klass;
this.method = method;
}
// 我们要拦截,当然只需知道我们拦截的是哪个类的哪个方法就行了
// 当然下面还有equals方法
InterceptorMethodDefination(***方法)
private Class<?> klass;
private Method method;
private Object object;
// 身为***:我们当然要执行,通过反射机制,所以object必不可少
// 构造方法
// 。。。
// get和set方法
InterceptorFactory
联系被拦截的目标和***链
private static final Map<InterceptorTargetDefination, List<InterceptorMethodDefination>> beforeMap;
private static final Map<InterceptorTargetDefination, List<InterceptorMethodDefination>> afterMap;
private static final Map<InterceptorTargetDefination, List<InterceptorMethodDefination>> exceptionMap;
static {
beforeMap = new HashMap<>();
afterMap = new HashMap<>();
exceptionMap = new HashMap<>();
}
public static void addBeforeInterceptor(InterceptorTargetDefination target,
InterceptorMethodDefination interceptor) {
addInterceptor(beforeMap, target, interceptor);
}
private static void addInterceptor(Map<InterceptorTargetDefination, List<InterceptorMethodDefination>> map,
InterceptorTargetDefination target,
InterceptorMethodDefination interceptor) {
List<InterceptorMethodDefination> interceptorList = map.get(target);
if (interceptorList == null) {
synchronized (InterceptorFactory.class) {
if (interceptorList == null) {
interceptorList = new ArrayList<>();
map.put(target, interceptorList);
}
}
}
interceptorList.add(interceptor);
}
// 这是添加***的方法:这里我给出添加前置***的方法,后置和异常同理
// 通过被拦截目标从Map中获得其***链,给***链添加***
// 注意!这里为了安全添加了锁,来保证每个目标的***链只有一个
另外,提供了get***链的方法,以前置***为例
public static List<InterceptorMethodDefination> getBeforeInterceptorList(
InterceptorTargetDefination target) {
return beforeMap.get(target);
}
Proxyfactory
提供两种方式构建代理 设置FyProxy
private FyProxy fyProxy;
public Proxyfactory() {
}
public FyProxy getFyProxy() {
return fyProxy;
}
CGLIB方式
public <T> T getCglibProxy(Class<?> klass, Object object) {
fyProxy = new FyProxy();
T proxy = cglibProxy(klass, object);
fyProxy.setProxy(proxy);
fyProxy.setObject(object);
return proxy;
}
@SuppressWarnings("unchecked")
private <T> T cglibProxy(Class<?> klass, Object object) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(klass);
enhancer.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy)
throws Throwable {
return doInvoker(klass, object, method, args);
}
});
return (T) enhancer.create();
}
JDK方式
public <T> T getJdkProxy(Class<?> klass, Object object) {
fyProxy = new FyProxy();
T proxy = jdkProxy(klass, object);
fyProxy.setProxy(proxy);
fyProxy.setObject(object);
return proxy;
}
@SuppressWarnings("unchecked")
private <T> T jdkProxy(Class<?> klass, Object object) {
ClassLoader classLoader = klass.getClassLoader();
Class<?>[] interfaces = klass.getInterfaces();
return (T) Proxy.newProxyInstance(classLoader, interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return doInvoker(klass, object, method, args);
}
});
}
代理对象中的内部方法
@SuppressWarnings("unchecked")
private <T> T doInvoker(Class<?> klass, Object object, Method method, Object[] args) throws Throwable {
Object result = null;
if (fyProxy.doBefore(klass, method, args)) {
try {
result = method.invoke(object, args);
fyProxy.doAfter(klass, method, result);
} catch (Throwable th) {
fyProxy.doException(klass, method, th);
}
}
return (T) result;
}
// 看,在这里我用到了FyProxy中的doBefore等方法
// 可以看出代理对象执行真正原对象方法的时候用的object还是原对象自己
// 代理就是 穿了一层“衣服”而已
ProxyBeanFactory
将类名与FyProxy对应形成Map
private static final Map<String, FyProxy> beanMap;
private static final Map<String, String> beanNameMap;
static {
beanMap = new HashMap<>();
beanNameMap = new HashMap<>();
}
// beanNameMap是类名和注解自定义名字的对应(因为考虑到使用者会在注解中给类名别的“称谓”)
public <T> T creatCglibProxy(Class<?> klass) throws Exception {
return cglibProxy(klass, klass.newInstance());
}
public <T> T creatCglibProxy(Object object) {
return cglibProxy(object.getClass(), object);
}
// 以CGLIB方式为例:
// 这里的目的是最上层创建代理并将其加入Map中
// 若该类已经存在代理,即fyProxy对象
// 则直接返回该对象
@SuppressWarnings("unchecked")
private <T> T cglibProxy(Class<?> klass, Object object) {
String className = klass.getName();
FyProxy fyProxy = beanMap.get(className);
if (fyProxy != null) {
return (T) fyProxy.getProxy();
}
Proxyfactory proxyfactory = new Proxyfactory();
T proxy = proxyfactory.getCglibProxy(klass, object);
beanMap.put(className, proxyfactory.getFyProxy());
return proxy;
}
public void addBeanName(String className, String beanName) throws BeanNameAlreadyExistException {
String orgClassName = beanNameMap.get(className);
if (orgClassName != null) {
throw new BeanNameAlreadyExistException("Bean名称(" + beanName + ")重复!");
}
beanNameMap.put(className, beanName);
}
// 这个是增加类名和用户注解中自定义类名的对应关系
这个类中还有,根据类或类名getFyproxy的方法,直接从map里面拿,代码也就不贴了。
下面在开始最核心的包扫描和依赖注入的那层之前,一定要先介绍一下我的注解
注解:
***的注解
// 包含***的类
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Aspect {
}
// 前置***方法
// 参数需给出,该***方法是作用于哪个类的哪个方法的
method不填为*号表示 :会给该类的所有方法增加该***
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Before {
Class<?> klass();
String method() default "*";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface After {
Class<?> klass();
String method() default "*";
Class<?>[] parameterTypes();
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface ThrowException {
Class<?> klass();
String method() default "*";
}
注入的注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Component {
String name() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface Bean {
String name() default "";
}
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface Autowired {
String name() default "";
}
BeanFactory
扫描出所有bean创建其代理(FyProxy)并加到ProxyBeanFactory中的Map中
包扫描代码在我前几篇博客中发过 >>传送门<<
// 给定包路径,扫描此包
public static void scanPackage(String packageName) throws Exception {
ProxyBeanFactory proxyBeanFactory = new ProxyBeanFactory();
// 该list的作用?别急,看下面
List<BeanMethodDefination> methodList = new ArrayList<>();
new PackageScanner() {
// 这里是个内部类,看过我包扫描代码的人应该了解
// 这里在循环中
@Override
public void dealClass(Class<?> klass) {
// 扫描出带有Component的类
if (!klass.isAnnotationPresent(Component.class)) {
return;
}
Component component = klass.getAnnotation(Component.class);
String name = component.name();
try {
// 创建该类的代理
proxyBeanFactory.creatCglibProxy(klass);
creatBean(null, klass, name, proxyBeanFactory);
// 执行该类中所有带有Bean注解的方法
// 并执行
// 执行时肯定要原类的对象
// 这就是我在FyProxy中存原类对象的原因
FyProxy fyProxy = proxyBeanFactory.getFyProxy(klass);
Object object = fyProxy.getObject();
Method[] methods = klass.getDeclaredMethods();
for (Method method : methods) {
if (!method.isAnnotationPresent(Bean.class)) {
continue;
}
// 执行方法
invokeBeanMethod(object, method, proxyBeanFactory, methodList);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}.packageScanner(packageName);
// 在所有类扫描完毕后
// 这里遍历了那个list
// 然后执行list中的method
// 这个list里面其实是带有参数的方法
// 为了解决带参方法参数需要对象而该对象所属类没被扫描到的问题
for (BeanMethodDefination beanMethod : methodList) {
Class<?> returnType = beanMethod.getReturnType();
Parameter[] paras = beanMethod.getParameters();
Object object = beanMethod.getObject();
String beanName = beanMethod.getBeanName();
Method method = beanMethod.getMethod();
// 执行多参方法
Object result = invokeMuliParaMethod(object, method, paras, proxyBeanFactory);
// 创建bean
creatBean(result, returnType, beanName, proxyBeanFactory);
}
}
上面List中放的是BeanMethodDefination,这里有必要说下他 五个成员 + 构造方法 + get和set
private Method method;
private Object object;
private Class<?> returnType;
private Parameter[] parameters;
private String beanName;
处理扫描到的Bean
private static void invokeBeanMethod(Object object, Method method,
ProxyBeanFactory proxyBeanFactory, List<BeanMethodDefination> methodList)
throws Exception {
// 获得方法返回值类型
Class<?> returnType = method.getReturnType();
// 需判断,若该方法返回void,无须执行,咱这是要得到Bean!
if (method.getReturnType().equals(void.class)) {
return;
}
// 下面判断方法参数个数,有参应在无参方法全部处理完再处理
// 所以用到了list
Bean bean = method.getAnnotation(Bean.class);
String beanName = bean.name();
Parameter[] parameters = method.getParameters();
int count = parameters.length;
if (count <= 0) {
// 无参方法直接执行并创建bean
Object result = method.invoke(object);
creatBean(result, returnType, beanName, proxyBeanFactory);
} else {
methodList.add(new BeanMethodDefination(method, object, returnType, parameters, beanName));
}
}
最后处理多参的Bean,遍历其参数,并设置
private static Object invokeMuliParaMethod(Object object, Method method,
Parameter[] parameters, ProxyBeanFactory proxyBeanFactory) throws Exception {
int count = parameters.length;
Object paras[] = new Object[count];
for (int index = 0; index < count; index++) {
Parameter parameter = parameters[index];
String className = parameter.getType().getName();
FyProxy fyProxy = proxyBeanFactory.getFyProxy(className);
Object beanObject = fyProxy.getObject();
if (beanObject != null) {
paras[index] = parameter;
}
}
return method.invoke(object, paras);
}
构建出Bean(代理)
private static void creatBean(Object result, Class<?> klass, String beanName, ProxyBeanFactory proxyBeanFactory)
throws Exception {
if (result != null) {
proxyBeanFactory.creatCglibProxy(result);
} else {
proxyBeanFactory.creatCglibProxy(klass);
}
if (beanName.length() > 0) {
proxyBeanFactory.addBeanName(klass.getName(), beanName);
}
}
注入!!!
当getBean时需要注入
@SuppressWarnings("unchecked")
public static <T> T getBean(Class<?> klass) {
ProxyBeanFactory proxyBeanFactory = new ProxyBeanFactory();
FyProxy fyProxy = proxyBeanFactory.getFyProxy(klass);
if (!fyProxy.isInjection()) {
injectBean(proxyBeanFactory, klass, fyProxy.getObject());
}
return (T) fyProxy.getProxy();
}
public static void injectBean(ProxyBeanFactory proxyBeanFactory, Class<?> klass,
Object object) {
// 获得该klass所需要的所有成员
// 遍历
// 判断其是否有Autowired注解
// 有则在ProxyBeanFactory中找到代理,将其设置为已注入(为解决循环依赖问题)
// 判断该成员的类是否也已经注入
// 若没有
// 则递归
// 最后将对象赋给成员 完成注入!!
Field[] fields = klass.getDeclaredFields();
for (Field field : fields) {
if (!field.isAnnotationPresent(Autowired.class)) {
continue;
}
FyProxy fyProxy = proxyBeanFactory.getFyProxy(klass);
fyProxy.setInjection(true);
Class<?> beanType = field.getType();
FyProxy fieldProxy = proxyBeanFactory.getFyProxy(beanType);
if (!fieldProxy.isInjection()) {
injectBean(proxyBeanFactory, beanType, fieldProxy.getObject());
}
field.setAccessible(true);
try {
field.set(object, fieldProxy.getObject());
} catch (IllegalArgumentException | IllegalAccessException e) {
e.printStackTrace();
}
}
}
InterceptorScanner
扫描并设置Bean的***,当然,要在扫描完Bean后再扫描***
扫描指定包路径,若含有Aspect注解,继续扫描其方法,根据注解信息为目标方法加上该***
public static void scanInterceptor(String packageName) {
new PackageScanner() {
@Override
public void dealClass(Class<?> klass) {
if (!klass.isAnnotationPresent(Aspect.class)) {
return;
}
try {
Object object = klass.newInstance();
Method[] methods = klass.getDeclaredMethods();
for (Method method : methods) {
if (method.isAnnotationPresent(Before.class)) {
Before before = method.getAnnotation(Before.class);
dealBeforeInterceptor(klass, object, method, before);
} else if (method.isAnnotationPresent(After.class)) {
After after = method.getAnnotation(After.class);
dealAfterInterceptor(klass, object, method, after);
} else if (method.isAnnotationPresent(ThrowException.class)) {
ThrowException throwException = method.getAnnotation(ThrowException.class);
dealExceptionInterceptor(klass, object, method, throwException);
}
}
} catch (InstantiationException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}
}.packageScanner(packageName);
}
添加***至指定方法的***链中,当然,不同***限制条件不同
当然,若注解中method默认为*,则给目标类中所有方法增加该***
private static void dealAfterInterceptor(Class<?> klass, Object object, Method method, After after)
throws Exception {
Class<?> returnType = method.getReturnType();
Class<?> targetClass = after.klass();
String targetMethodStr = after.method();
Method targetMethod = targetClass.getDeclaredMethod(targetMethodStr, after.parameterTypes());
Class<?> targetReturntype = targetMethod.getReturnType();
if (!returnType.equals(targetReturntype)) {
throw new WrongOfAfterInterceptorReturnType("后置***(" + method + ")返回值不是" + targetReturntype);
}
if (targetMethodStr.equals("*")) {
Method[] methods = targetClass.getDeclaredMethods();
for (Method targetAllMethod : methods) {
InterceptorTargetDefination target = new InterceptorTargetDefination(targetClass, targetAllMethod);
InterceptorMethodDefination interceptor = new InterceptorMethodDefination(klass, method, object);
InterceptorFactory.addAfterInterceptor(target, interceptor);
}
} else {
InterceptorTargetDefination target = new InterceptorTargetDefination(targetClass, targetMethod);
InterceptorMethodDefination interceptor = new InterceptorMethodDefination(klass, method, object);
InterceptorFactory.addAfterInterceptor(target, interceptor);
}
}
前置
private static void dealBeforeInterceptor(Class<?> klass, Object object, Method method, Before before)
throws Exception {
Class<?> returnType = method.getReturnType();
if (!returnType.equals(boolean.class)) {
throw new WrongOfBeforeInterceptorReturnType("前置***(" + method + ")返回值只能是boolean类型");
}
Class<?> targetClass = before.klass();
String targetMethodStr = before.method();
if (targetMethodStr.equals("*")) {
Method[] methods = targetClass.getDeclaredMethods();
for (Method targetMethod : methods) {
InterceptorTargetDefination target = new InterceptorTargetDefination(targetClass, targetMethod);
InterceptorMethodDefination interceptor = new InterceptorMethodDefination(klass, method, object);
InterceptorFactory.addBeforeInterceptor(target, interceptor);
}
} else {
Method targetMethod = targetClass.getDeclaredMethod(before.method(), method.getParameterTypes());
InterceptorTargetDefination target = new InterceptorTargetDefination(before.klass(), targetMethod);
InterceptorMethodDefination interceptor = new InterceptorMethodDefination(klass, method, object);
InterceptorFactory.addBeforeInterceptor(target, interceptor);
}
}
异常
private static void dealExceptionInterceptor(Class<?> klass, Object object, Method method, ThrowException throwException)
throws Exception {
Class<?> returnType = method.getReturnType();
if (!returnType.equals(void.class)) {
throw new ExceptionInterceptorReturnTypeNotVoid("异常***(" + method + ")返回值不是void类型");
}
Class<?>[] parameterTypes = method.getParameterTypes();
if (parameterTypes.length != 1 || parameterTypes[0].equals(Throwable.class)) {
throw new WrongOfExceptionInterceptorReturnType("异常***(" + method + ")参数类型必须是Throwable");
}
Class<?> targetClass = throwException.klass();
String targetMethodStr = throwException.method();
if (targetMethodStr.equals("*")) {
Method[] methods = targetClass.getDeclaredMethods();
for (Method targetMethod : methods) {
InterceptorTargetDefination target = new InterceptorTargetDefination(targetClass, targetMethod);
InterceptorMethodDefination interceptor = new InterceptorMethodDefination(klass, method, object);
InterceptorFactory.addExceptionInterceptor(target, interceptor);
}
} else {
Method targetMethod = targetClass.getDeclaredMethod(targetMethodStr, method.getParameterTypes());
InterceptorTargetDefination target = new InterceptorTargetDefination(throwException.klass(), targetMethod);
InterceptorMethodDefination interceptor = new InterceptorMethodDefination(klass, method, object);
InterceptorFactory.addExceptionInterceptor(target, interceptor);
}
}
以上就是自己实现AOP IOC的全部内容,当然也有许多不足的地方,往各位多多提意见!