利用cglib包实现Spring中aop的功能

时间:2023-03-09 15:45:47
利用cglib包实现Spring中aop的<aop:advisor>功能

一:前言

  还有<aop:before>/<aop:after>/<aop:around>的没有实现,不过根<aop:advisor>是差不多的,就是要额外注册一些东西到AdvisorSupport里,这个等以后有时间再写了;

二:代码

1.Test类,用于描述<aop:pointcut的expression属性,即调用时这个类中声明的方法不会实施aop拦截

package me.silentdoer.aoprealization.action;

/**
* @author silentdoer
* @version 1.0
* @description the description
* @date 4/28/18 2:50 PM
*/
public class Test {
public void printSS(){
System.out.println("UXXXXXXXXXXXss");
}
}

2.AopTest类,即aspect类(如StudentServiceImpl之类的)

package me.silentdoer.aoprealization.action;

/**
* @author silentdoer
* @version 1.0
* @description 作为pointcut的提供类
* @date 4/27/18 8:14 PM
*/
public class AopTest extends Test{
public void foo(){
System.out.println("Hello, llll");
System.out.println(foo2(88));
} private String foo2(int num){
System.out.println(String.format("The string is %s", num));
return (num + 100) + "";
}
}

3.FooAdviceForAdvisor类,即advisor的实现类

package me.silentdoer.aoprealization.aop.advice;

import net.sf.cglib.proxy.MethodProxy;
import org.aopalliance.aop.Advice;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation; import java.lang.reflect.Method; /**
* @author silentdoer
* @version 1.0
* @description 通过直接实现MethodInterceptor来实现Spring中的<aop:advisor ..></aop:advisor>
* @date 4/27/18 8:32 PM
*/
public class FooAdviceForAdvisor implements MethodInterceptor{
@Override
public Object invoke(MethodInvocation methodInvocation) throws Throwable {
System.out.println("Before部分");
//System.out.println(methodInvocation.getClass());
Object result = methodInvocation.proceed();
System.out.println("After部分");
return result;
}
}

4.AopSupport类,实现用户配置和具体产生代理类分离的中间类(around/before/after配置也可以通过这种方式实现)

package me.silentdoer.aoprealization.aop.support;

import me.silentdoer.aoprealization.aop.method.DefaultMethodInvocation;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy; import java.lang.reflect.Method;
import java.util.List; /**
* @author silentdoer
* @version 1.0
* @description 这个类在实际中不允许用户主动使用
* @date 4/28/18 2:53 PM
*/
public class AopSupport implements MethodInterceptor {
private List<Method> pointcuts;
private org.aopalliance.intercept.MethodInterceptor advisor; @Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
final Method met = method;
if (this.pointcuts.stream().anyMatch(m -> m.equals(met))){
DefaultMethodInvocation methodInvocation = new DefaultMethodInvocation();
methodInvocation.setTarget(o);
methodInvocation.setMethod(method); // 要通过适配器模式将MethodProxy转换为Method(Method是final无法适配,只好添加MethodProxy属性
methodInvocation.setRealMethod(methodProxy);
methodInvocation.setArgs(objects);
return advisor.invoke(methodInvocation);
}else{
return methodProxy.invokeSuper(o, objects);
}
} public void setPointcuts(List<Method> pointcuts) {
this.pointcuts = pointcuts;
} public void setAdvisor(org.aopalliance.intercept.MethodInterceptor advisor){
this.advisor = advisor;
}
}

5.DefaultMethodInvocation类,用于实现method/args/target的一体化

package me.silentdoer.aoprealization.aop.method;

import net.sf.cglib.proxy.MethodProxy;
import org.aopalliance.intercept.MethodInvocation; import java.lang.reflect.AccessibleObject;
import java.lang.reflect.Method; /**
* @author silentdoer
* @version 1.0
* @description the description
* @date 4/28/18 8:38 PM
*/
public class DefaultMethodInvocation implements MethodInvocation{
private Method method;
private MethodProxy realMethod;
private Object[] args;
private Object target; @Override
public Method getMethod() {
return this.method;
} @Override
public Object[] getArguments() {
return this.args;
} @Override
public Object proceed() throws Throwable {
return this.realMethod.invokeSuper(this.target, args);
} @Override
public Object getThis() {
return this.target;
} @Override
public AccessibleObject getStaticPart() {
return this.method;
} public void setMethod(Method method) {
this.method = method;
} public void setArgs(Object[] args) {
this.args = args;
} public void setTarget(Object target) {
this.target = target;
//System.out.println(this.target == null);
} public void setRealMethod(MethodProxy realMethod) {
this.realMethod = realMethod;
}
}

6.main方法所在类,兼具解析xml和装配代理类的作用(demo主要是为了了解aop的实现原理)

package me.silentdoer.aoprealization;

import me.silentdoer.aoprealization.action.AopTest;
import me.silentdoer.aoprealization.aop.advice.FooAdviceForAdvisor;
import me.silentdoer.aoprealization.aop.support.AopSupport;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import org.dom4j.Document;
import org.dom4j.DocumentException;
import org.dom4j.Element;
import org.dom4j.io.SAXReader; import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List; /**
* @author silentdoer
* @version 1.0
* @description 这里就简单的实现advisor的aop,且expression默认是某个类中所有的declare的方法
* @date 4/27/18 4:56 PM
*/
public class Entrance {
private static Element root;
private static AopTest fooBean; public static void main(String[] args) throws DocumentException, ClassNotFoundException, IllegalAccessException, InstantiationException {
org.dom4j.io.SAXReader reader = new SAXReader();
ClassLoader classLoader = Thread.currentThread().getContextClassLoader();
Document document = reader.read(classLoader.getResource("aop.xml"));
root = document.getRootElement();
List<Element> elements = root.elements(); Class beanClazz = classLoader.loadClass(elements.stream().filter((e) -> e.attributeValue("id").equals("aopTest")).findFirst().get().attributeValue("class"));
//System.out.println(beanClazz); //me.silentdoer.aoprealization.action.AopTest
// TODO 这个是没有加aop功能时原始的bean,这步可以理解为getBean
fooBean = (AopTest) beanClazz.newInstance();
fooBean.foo(); System.out.println("<------------------------------------------------------->"); // TODO 实现BeanFactoryPostProcessor接口的扫描配置文件来为对应的bean组装aop功能
Element config = elements.stream().filter(e -> e.getName().equals("config")).findFirst().get();
parseAopConfig(config);
// 动态代理类实现aop功能,但是对于非DeclaredMethod不会做切面拦截处理,比如在Test中的printSS方法;
fooBean.foo(); // 实现aop拦截
System.out.println("<---------------------------------------------------------------->");
fooBean.printSS(); // 不符合expression因此即便为fooBean配置了aop对于此方法也不会实施aop功能
} // 根据<aop:config来“重建”需要aop功能的bean,这里就是fooBean
private static void parseAopConfig(Element config){
// TODO 这里认定pointcut的expression是获取originBean的所有的DeclaredMethod方法
Element pointcutElem = config.element("pointcut");
List<Method> pointcuts = parsePointcuts(pointcutElem);
Element advisorElem = config.element("advisor");
// TODO 这里通过advisorElem得到用户自定义的advisor类对象
FooAdviceForAdvisor advisorBean = getUserAdvisor(advisorElem);
// TODO 根据advisor和pointcut组装成一个新的MethodInterceptor对象,这个interceptor是实现了expression和advisor联合的拦截者
MethodInterceptor realInterceptor = parseAdvisor(advisorBean, pointcuts);
// TODO 根据配置得知fooBean是需要加上aop功能,因此通过Enhancer重新生成新的bean覆盖老的bean,这步在Spring里是通过实现了BeanFactoryPostProcessor接口的类里执行的
fooBean = (AopTest) Enhancer.create(AopTest.class, realInterceptor);
} private static MethodInterceptor parseAdvisor(org.aopalliance.intercept.MethodInterceptor advisor, List<Method> pointcuts){
// 正式情况下AdvisorSupport是包访问权限,而这部分代码也是在和此类同一个包里面实现的因此AdvisorSupport是系统组件不由用户手动创建
AopSupport result = new AopSupport();
result.setAdvisor(advisor);
result.setPointcuts(pointcuts);
return result;
} private static List<Method> parsePointcuts(Element aopPointcut){
// TODO 本来应该通过aopPointcut的expression来获取,不过这个主要是实现aop对表达式的解析忽略
return Arrays.asList(AopTest.class.getDeclaredMethods());
} // 根据advisor-ref获取advisor对象
private static FooAdviceForAdvisor getUserAdvisor(Element advisor){
FooAdviceForAdvisor result = new FooAdviceForAdvisor();
return result;
}
}

7.aop.xml配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns:aop="silentdoer"> <!-- 模拟注册到Spring里管理,这里则只是简单的通过dom4j来搜索 -->
<bean id="aopTest" class="me.silentdoer.aoprealization.action.AopTest"/> <bean id="fooAdvisor" class="me.silentdoer.aoprealization.aop.advice.FooAdviceForAdvisor"/>
<aop:config>
<!-- 这里暂且认为me.silentdoer.aoprealization.action.AopTest.*就是AopTest中所有Declared的方法 -->
<aop:poincut id="pointcut1" expression="me.silentdoer.aoprealization.action.AopTest.*"/>
<aop:advisor advisor-ref="fooAdvisor" poincut-ref="pointcut1"/>
</aop:config> <!--<bean id="fooAdvice" class="me.silentdoer.aoprealization.aop.advice.FooAdvice"/>
<aop:config>
<aop:pointcut id="pointcut2" expression="me.silentdoer.aoprealization.action.AopTest.*"/>
<aop:aspect ref="fooAdvice">
<aop:around method="around" poincut-ref="poincut2"/>
</aop:aspect>
</aop:config>-->
</beans>