自行一个简单类似Spring AOP(Jdk方式)的框架

Posted javartisan

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了自行一个简单类似Spring AOP(Jdk方式)的框架相关的知识,希望对你有一定的参考价值。

Spring AOP有两种实现方式,一种是基于JDK的,另一种是基于Cglib的,本文模拟Spring的Jdk实现方式自行实现一个简单的小框架,目的是熟悉思想。

 

基于JDK的动态代理,最终的一个类是InvocationHandler,InvocationHandler可以理解为一个方法调用器,在对方法进行增强时候,代理类会拦截到目标对象上的方法,然后将拦截的方法传递给InvocationHandler的invoke方法,在invoke中触发方法调用,此时就可以对方法调用前后进行逻辑增强。因此需要我们实现一个方法调用器,代码如下:


import org.springframework.util.StringUtils;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * 方法调用器
 * @param <T>
 */
public class ProxyInvocationHandler<T> implements InvocationHandler 

    private T target;

    public ProxyInvocationHandler(T target) 
        this.target = target;
    

    private Advice[] advices;
    private String beforeMethodName = "before";
    private String afterMethodName = "after";

    private Method beforeMethod;

    public Advice[] getAdvices() 
        return advices;
    

    public void setAdvices(Advice[] advices) 
        this.advices = advices;
    

    private Method afterMethod;

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable 

        AdviceParam adviceParam = new AdviceParam();
        adviceParam.setTarget(target);
        adviceParam.setParams(args);
        adviceParam.setMethod(method);
        
        //调用前增强
        for (int i = 0; i < advices.length; i++) 
            Advice advice = advices[i];
            if (!StringUtils.isEmpty(beforeMethodName)) 
                beforeMethod = getMethod(advice, beforeMethodName);
                beforeMethod.invoke(advice, adviceParam);
            
        
        // 拦截方法调用
        Object result = method.invoke(target, args);
        adviceParam.setResult(result);
        
        // 调用之后增强
        for (int i = advices.length - 1; i >= 0; i--) 
            Advice advice = advices[i];
            if (!StringUtils.isEmpty(afterMethodName)) 
                afterMethod = getMethod(advice, afterMethodName);
                afterMethod.invoke(advice, adviceParam);
            
        

        return adviceParam.getResult();
    

    /**
     * 可以考虑添加cache提高性能
     *
     * @param name
     * @return
     */
    public Method getMethod(Advice advice, String name) 

        if (!StringUtils.isEmpty(name)) 
            Method[] methods = advice.getClass().getDeclaredMethods();
            for (Method method : methods) 
                if (method.getName().equalsIgnoreCase(name)) 
                    method.setAccessible(true);
                    return method;
                
            
        

        return null;
    

方法调用器便编写好了;Spring中对于增强的逻辑进行了一些封装抽象,我们这里面也模拟进行了一些简单的封装抽象。封装的对象有Advice,Advice就是增强逻辑的实现,Advice中有两个方法,分别是前置增强,后置增强(更多增强类似);当拦截的方法传递invoke方法时候便会对前置后置增强逻辑进行调用,以达到增强的目的。

接下来一步便是生成代理类,Spring中使用工厂的方式进行生成代理类,本示例模拟Spring的设计进行简单实现一个代理类生成工厂,先给出类的继承结构:

其中AopConfig是用于存储Aop的配置信息,ProxyFactory是一个抽象工厂,后序可以分为JDK与Cglib两种实现,本文给出JDK实现:

import java.lang.reflect.Proxy;

public class JdkProxyFactory<T> extends ProxyFactory<T> 

    @Override
    public T getProxy() 

        ProxyInvocationHandler handler = new ProxyInvocationHandler(this.getTarget());
        handler.setAdvices(this.getAdvices());
        return (T) Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), this.getClazz(), handler);
    

到此也就实现了一个简单的Aop框架,接下来就可以测试,增强代码:

import com.javartisan.service.jdk.proxy.Advice;
import com.javartisan.service.jdk.proxy.AdviceParam;

public class LogAdvice implements Advice 
    @Override
    public Object before(AdviceParam args) 
        System.out.println("before = " + args);
        return null;
    

    @Override
    public Object after(AdviceParam args) 
        System.out.println("after = " + args);
        return null;
    

测试代码:


import com.javartisan.service.UserService;
import com.javartisan.service.UserServiceImpl;
import com.javartisan.service.jdk.proxy.JdkProxyFactory;
import com.javartisan.service.jdk.proxy.ProxyFactory;

import java.util.Arrays;

public class JdkProxy 

    public static void main(String[] args) 

        UserService userService = new UserServiceImpl();

        ProxyFactory<UserService> proxyFactory = new JdkProxyFactory<>();
        proxyFactory.setTarget(userService);
        proxyFactory.setClazz(new Class[]UserService.class);
        proxyFactory.setAdvices(Arrays.asList(new LogAdvice(), new LogAdvice()));

        UserService proxy = proxyFactory.getProxy();

        System.out.println(proxy.login("daxin"));

        // proxy是代理类
        System.out.println(proxy.getClass());

    

输出:

before = AdviceParamtarget=com.javartisan.service.UserServiceImpl@2ff4acd0, params=[daxin], method=public abstract boolean com.javartisan.service.UserService.login(java.lang.String), result=null
before = AdviceParamtarget=com.javartisan.service.UserServiceImpl@2ff4acd0, params=[daxin], method=public abstract boolean com.javartisan.service.UserService.login(java.lang.String), result=null
login false defalut
after = AdviceParamtarget=com.javartisan.service.UserServiceImpl@2ff4acd0, params=[daxin], method=public abstract boolean com.javartisan.service.UserService.login(java.lang.String), result=false
after = AdviceParamtarget=com.javartisan.service.UserServiceImpl@2ff4acd0, params=[daxin], method=public abstract boolean com.javartisan.service.UserService.login(java.lang.String), result=false
false
class com.sun.proxy.$Proxy0

 

Github仓库位置:https://github.com/javartisan/javartisan-cglib ,欢迎点星。

 

以上是关于自行一个简单类似Spring AOP(Jdk方式)的框架的主要内容,如果未能解决你的问题,请参考以下文章

Spring AOP:jdk动态代理

Spring AOP:jdk动态代理

Java通过JDK动态代理简单的实现一个AOP

Java--简单的Spring AOP配置以及AOP事物管理,JDK/GCLib动态代理

Spring的学习(Spring中的AOP)

spring AOP