这个系列是基于小傅哥的「手撸 Spring」学习的一个记录
AOP 意为面向切面编程,通过预编译的方式和运行期间动态代理实现程序功能的统一维护。这句话可能不太好理解,可以先看下图:
从图中可以看出, AOP 的作用就是在对某些具有共同特点的方法进行拦截,并执行方法拦截器中的功能,完成对原有方法的功能的扩展。
这一次首先是要实现一个简单的切面功能。
首先从代理一个方法,来观察代理方法的过程。
public void test_proxy_method() {
Object targetObj = new UserService();
IUserService proxy = (IUserService) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), targetObj.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.currentTimeMillis();
Object value= method.invoke(targetObj, args);
long end = System.currentTimeMillis();
System.out.println("程序执行时间=" + (end-start) + "ms");
return value;
}
});
proxy.queryUserInfo();
}
在这个代码中,我们对需要 targetObj 接口的实现类进行了代理。在 AOP 的实现过程中,需要对这个过程进行进一步的抽象。
接下来,就可以根据这些点来看一个简易的 AOP 是怎么完成的了。
这个是完成简易 AOP 功能的类图,看起来很复杂,但是仔细解析一下,就发现其实并不是很难。
public interface PointCut {
ClassFilter getClassFilter();
MethodMatcher getMethodMatcher();
}
public interface ClassFilter {
boolean matches(Class<?> clazz);
}
public interface MethodMatcher {
boolean matches(Method method, Class<?> targetClass);
}
AspectJExpressionPointcut 这个类继承了上述三个接口,完成了对具体表达式的解析和匹配规则,这里的匹配规则直接调用了 aspectjweaver 的实现。
public class AspectJExpressionPointcut implements PointCut, ClassFilter, MethodMatcher {
private static final Set<PointcutPrimitive> SUPPORTED_PRIMITIVES = new HashSet<>();
static {
SUPPORTED_PRIMITIVES.add(PointcutPrimitive.EXECUTION);
}
private final PointcutExpression pointcutExpression;
public AspectJExpressionPointcut(String expression) {
PointcutParser pointCutParse = PointcutParser.
getPointcutParserSupportingSpecifiedPrimitivesAndUsingSpecifiedClassLoaderForResolution(SUPPORTED_PRIMITIVES, this.getClass().getClassLoader());
pointcutExpression = pointCutParse.parsePointcutExpression(expression);
}
@Override
public boolean matches(Class<?> clazz) {
return pointcutExpression.couldMatchJoinPointsInType(clazz);
}
@Override
public boolean matches(Method method, Class<?> targetClass) {
return pointcutExpression.matchesMethodExecution(method).alwaysMatches();
}
@Override
public ClassFilter getClassFilter() {
return this;
}
@Override
public MethodMatcher getMethodMatcher() {
return this;
}
}
在这一步,其实已经完成了对方法的拦截,可以测试一下。
public void test_aop() throws NoSuchMethodException {
AspectJExpressionPointcut pointcut = new AspectJExpressionPointcut("execution(* cn.wufu.springframework.bean.UserService.*(..))");
Class<UserService> clazz = UserService.class;
Method method = clazz.getDeclaredMethod("queryUserInfo");
System.out.println(pointcut.matches(clazz));
System.out.println(pointcut.matches(method, clazz));
}
这个类主要是持有了被代理对象、方法拦截器、方法匹配器,这是完成代理的重要组成部分,这里将其包装到一个类中,方便后续使用。
自定义的拦截器就是注入到这个类中。
public class AdvisedSupport {
/**
* 要代理的对象
*/
private TargetSource targetSource;
/**
* 拦截器,对代理对象的功能进行增强
*/
private MethodInterceptor methodInterceptor;
/**
* 方法匹配,判断方法是不是需要被
*/
private MethodMatcher methodMatcher;
public MethodInterceptor getMethodInterceptor() {
return methodInterceptor;
}
// 省略 get/set 方法
}
/**
* 目标对象,提供 Object 入参属性以及获取目标类 TargetClass 信息
* @author wufu
*/
public class TargetSource {
private final Object target;
public TargetSource(Object target) {
this.target = target;
}
public Class<?>[] getTargetClass() {
return this.target.getClass().getInterfaces();
}
public Object getTarget() {
return target;
}
}
这里实现两种方式一种是 JDK 方式,一种是 Cglib 方式,所以首先定义一个接口 AopProxy。
public interface AopProxy {
/**
* 获取代理类,具体实现代理的方式有两种:JDK 方式、Cglib 方式
* @return
*/
Object getProxy();
}
// JDK 实现方式
public class JdkDynamicAopProxy implements AopProxy, InvocationHandler {
private final AdvisedSupport advised;
public JdkDynamicAopProxy(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object getProxy() {
return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(),
advised.getTargetSource().getTargetClass(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
MethodInterceptor methodInterceptor = advised.getMethodInterceptor();
return methodInterceptor.invoke(new ReflectiveMethodInvocation(advised.getTargetSource().getTarget(), method, args));
}
return method.invoke(advised.getTargetSource().getTarget(), args);
}
}
// cglib 实现方式
public class CglibAopProxy implements AopProxy{
private final AdvisedSupport advised;
public CglibAopProxy(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object getProxy() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(advised.getTargetSource().getTarget().getClass());
enhancer.setInterfaces(advised.getTargetSource().getTargetClass());
enhancer.setCallback(new DynamicAdvisedInterceptor(advised));
return enhancer.create();
}
private static class DynamicAdvisedInterceptor implements MethodInterceptor {
private final AdvisedSupport advised;
public DynamicAdvisedInterceptor(AdvisedSupport advised) {
this.advised = advised;
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
CglibMethodInvocation methodInvocation = new CglibMethodInvocation(advised.getTargetSource().getTarget(), method, objects, methodProxy);
if (advised.getMethodMatcher().matches(method, advised.getTargetSource().getTarget().getClass())) {
return advised.getMethodInterceptor().invoke(methodInvocation);
}
return methodInvocation.proceed();
}
}
private static class CglibMethodInvocation extends ReflectiveMethodInvocation {
private final MethodProxy methodProxy;
public CglibMethodInvocation(Object target, Method method, Object[] arguments, MethodProxy methodProxy) {
super(target, method, arguments);
this.methodProxy = methodProxy;
}
@Override
public Object proceed() throws Throwable {
return this.methodProxy.invoke(this.target, this.arguments);
}
}
}
这两种方式只需要看他共性的部分:一个是 JDK 方式中的 invoke 方法,一个是 cglib 中的 DynamicAdvisedInterceptor 内部类的 intercept 方法,这两个方法中,如果匹配成功调用 methodInterceptor.invoke() 逻辑。
以下是准备的 IUserservice 接口、UserService 类以及自定义的拦截器 UserServiceInterceptor 。
public interface IUserService {
String queryUserInfo();
String register(String userName);
}
public class UserService implements IUserService{
public String queryUserInfo() {
return "wufu";
}
public String register(String userName) {
try {
Thread.sleep(new Random(1).nextInt(100));
} catch (InterruptedException e) {
e.printStackTrace();
}
return "注册用户:" + userName + " success!";
}
}
public class UserServiceInterceptor implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
long start = System.currentTimeMillis();
try {
return invocation.proceed();
} finally {
System.out.println("监控 - Begin By AOP");
System.out.println("方法名称:" + invocation.getMethod());
System.out.println("方法耗时:" + (System.currentTimeMillis() - start) + "ms");
System.out.println("监控 - End\r\n");
}
}
}
@Test
public void test_dynamic() {
IUserService userService = new UserService();
AdvisedSupport advisedSupport = new AdvisedSupport();
advisedSupport.setTargetSource(new TargetSource(userService));
advisedSupport.setMethodInterceptor(new UserServiceInterceptor());
advisedSupport.setMethodMatcher(new AspectJExpressionPointcut("execution(* cn.wufu.springframework.bean.IUserService.*(..))"));
IUserService proxy_jdk = (IUserService) new JdkDynamicAopProxy(advisedSupport).getProxy();
System.out.println("测试结果=" + proxy_jdk.queryUserInfo());
IUserService proxy_cglib = (IUserService) new CglibAopProxy((advisedSupport)).getProxy();
System.out.println("测试结果=" + proxy_cglib.register("wufu 02"));
}
这个部分设计比代码更重要一些,主要关注一下 AOP 的代码结构。