java动态代理和cglib动态代理的整合工具

1.解决大量共同业务的处理

2.解决jdk动态代理中实现类注解获取不到的困扰

3.使用业务链条模式进行前切和后切,可以做到用户自己随意对业务进行增减少

 

如果想要与spring整合,可以使用factory-method来进行代理对象的生成。

里面有之前一些博客得练习

csdn代码地址  https://code.csdn.net/w172087242/littlehow/tree/master

 

代码maven依赖:低版本的也可以,这里主要是使用spring集成的cglib包,所以需要引入spring-core


    junit
    junit
    4.10


    org.springframework
    spring-core
    4.3.3.RELEASE
 

 

 

 

jdk动态父类:处理实际的代理业务,以及缓存部分信息

package littlehow.proxy;

import littlehow.proxy.anno.AfterChain;
import littlehow.proxy.anno.BeforeChain;
import littlehow.proxy.anno.Cut;
import littlehow.proxy.chain.Chain;
import littlehow.proxy.chain.Context;
import littlehow.proxy.chain.ContextManager;
import littlehow.proxy.chain.EndChain;
import littlehow.proxy.enm.CutType;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.concurrent.ConcurrentHashMap;

/**
 * ProxyParant
 *
 * @author littlehow
 * @time 2016-09-26 13:52
 */
public class ProxyParant {
    protected T instance;
    //jdk动态代理时获取不到类中方法的注解
    protected HashMap jdkBeanMethods = new HashMap<>();
    //前切业务链
    protected ConcurrentHashMap beforeChains = new ConcurrentHashMap<>();
    //后切业务链
    protected ConcurrentHashMap afterChains = new ConcurrentHashMap<>();
    //所有业务的终点
    private static final EndChain end = new EndChain();

    /**
     * 执行实际方法
     * @param method
     * @param arguments
     * @return
     * @throws Throwable  -- 可能是切入时发生异常,也可能是执行方法发生异常,这里就不再进行处理了
     */
    public Object executeMethod(Method method, Object[] arguments) throws Throwable{
        String key = method.toString();
        //查询bean的方法,可能为null
        Method beanMethod = jdkBeanMethods.get(key);
        //切入方案
        Cut cut = null;
        //判断是否进行前切
        if(method.isAnnotationPresent(Cut.class)) {//优先从顶层取
            cut = method.getAnnotation(Cut.class);
        } else if(beanMethod != null && beanMethod.isAnnotationPresent(Cut.class)) {
            cut = beanMethod.getAnnotation(Cut.class);
        }
        if(cut == null) {
            return method.invoke(instance, arguments);
        }
        //设置上下文
        this.setContext(method, arguments, beanMethod);
        if((cut.value().getValue() & CutType.BEFORE.getValue()) != 0) {//进行前切
            this.before(method, arguments, beanMethod);
        }
        //执行业务
        Object result = method.invoke(instance, arguments);
        if((cut.value().getValue() & CutType.AFTER.getValue()) != 0) {//进行后切
            this.after(method, arguments, beanMethod);
        }
        //释放一次上下文
        end.invoke();
        return result;
    }

    /**
     * @param main
     * @param jdkClass -- jdk动态代理造成的接口和实现都出现chain的情况
     * @throws Throwable
     */
    private Chain getChain(Class[] main, Class[] jdkClass) throws Throwable{
        Chain current = null;
        Chain returnValue = null;
        if(main != null && main.length > 0) {
            current = main[0].newInstance();
            returnValue = current;
            for(int i=1,len=main.length; i < len; i++) {
                Chain chain = main[i].newInstance();
                current.setNext(chain);
                current = chain;
            }
        }
        if(jdkClass != null && jdkClass.length > 0) {
            int index = 0;
            if(current == null) {
                current = jdkClass[0].newInstance();
                returnValue = current;
                index ++;
            }
            for(int i=index,len=jdkClass.length; i < len; i++) {
                Chain chain = jdkClass[i].newInstance();
                current.setNext(chain);
                current = chain;
            }
        }
        //current.setNext(end);
        return returnValue;
    }

    /**
     * 设置当前上下文
     * @param method
     * @param arguments
     * @param beanMethod
     */
    private void setContext(Method method, Object[] arguments, Method beanMethod) {
        //设置上下文
        Context context = new Context(beanMethod == null ? method : beanMethod, arguments);
        ContextManager.set(context);
    }

    /**
     * 前切业务
     * @param method
     * @param arguments
     * @param beanMethod   -- jdk代理中的beanMethod
     */
    private void before(Method method, Object[] arguments, Method beanMethod) throws Throwable{
        Chain chainObj = beforeChains.get(method);
        if(chainObj == null) {
            Class[] main = null;
            Class[] jdkClass = null;
            if(method.isAnnotationPresent(BeforeChain.class)) {//如果有
                main = method.getAnnotation(BeforeChain.class).value();
            }
            if(beanMethod != null && beanMethod.isAnnotationPresent(BeforeChain.class)) {
                jdkClass = beanMethod.getAnnotation(BeforeChain.class).value();
            }
            chainObj = getChain(main, jdkClass);
            if(chainObj != null)
                beforeChains.put(method, chainObj);
        }
        if(chainObj != null) {//拥有业务链条
            chainObj.execute();
        }
    }

    /**
     * 后继业务
     * @param method
     * @param arguments
     * @param beanMethod  -- jdk代理中的beanMethod
     */
    private void after(Method method, Object[] arguments, Method beanMethod)  throws Throwable{
        Chain chainObj = afterChains.get(method);
        if(chainObj == null) {
            Class[] main = null;
            Class[] jdkClass = null;
            if(method.isAnnotationPresent(AfterChain.class)) {//如果有
                main = method.getAnnotation(AfterChain.class).value();
            }
            if(beanMethod != null && beanMethod.isAnnotationPresent(AfterChain.class)) {
                jdkClass = beanMethod.getAnnotation(AfterChain.class).value();
            }
            chainObj = getChain(main, jdkClass);
            if(chainObj != null)
                afterChains.put(method, chainObj);
        }
        if(chainObj != null) {//拥有业务链条
            chainObj.execute();
        }
    }
}

 

 

 

jdk代理类:处理jdk动态代理,并且缓存需要自己类注解的方法,便于处理注解

 

package littlehow.proxy;


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

/**
 * InvocationProxy  jdk动态代理生成类
 *
 * @author littlehow
 * @time 2016-09-26 11:42
 */
public class InvocationProxy extends ProxyParant implements InvocationHandler {
    /**
     * 生成代理对象
     * @param obj
     * @param  接口类型
     * @return
     */
    public static  T newInstance(T obj) {
        InvocationProxy invocationProxy = new InvocationProxy<>();
        Class clazz = obj.getClass();
        invocationProxy.instance = obj;
        //将类中拥有注解的方法进行缓存
        Class[] classes = obj.getClass().getInterfaces();
        for(Class clz : classes) {//由接口找出适配的方法,简单的根据tostring进行查询
            Method[] methods = clz.getMethods();
            for(Method m : methods) {
                try {
                    Method objMethod = clazz.getMethod(m.getName(), m.getParameterTypes());
                    //判断是否有注解,没有的话不进行保存
                    if(objMethod.getAnnotations().length > 0) {
                        invocationProxy.jdkBeanMethods.put(m.toString(), objMethod);
                    }
                } catch (Exception ex) {//主要处理NoSuchMethodException
                    //写入父类的方法不进行处理,因为这里主要处理的是注解在实现类中的差异,父类承接了和接口注解就一致了
                }
            }
        }
        return (T) Proxy.newProxyInstance(clazz.getClassLoader(),
                clazz.getInterfaces(), invocationProxy);
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] arguments) throws Throwable {
        return this.executeMethod(method, arguments);
    }
}

 

 

 

cglib代理类:

 

package littlehow.proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * Cglib动态代理
 *
 * @author littlehow
 * @time 2016-09-26 11:08
 */
public class CglibProxy extends ProxyParant implements MethodInterceptor {
    public static  T newCglibInstance(T obj) {
        CglibProxy cp = new CglibProxy<>();
        cp.instance = obj;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(obj.getClass());
        enhancer.setCallback(cp);
        return (T)enhancer.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] arguments, MethodProxy methodProxy) throws Throwable {
        return this.executeMethod(method, arguments);
    }
}

 

 

 

由是否有接口来简单判断是使用jdk代理还是cglib代理:

 

package littlehow.proxy;

/**
 * ProxyUtils
 *
 * @author littlehow
 * @time 2016-09-26 11:58
 */
public class ProxyUtils {

    /**
     * 获取代理对象
     * @param obj
     * @param 
     * @return
     */
    public static  T getProxyInstance(T obj) {
        if(obj == null) return null;
        //判断是否有接口,当前jdk版本返回的数组不可能为null,如果未实现接口,则数组长度为0
        Class[] interfaces = obj.getClass().getInterfaces();
        if (interfaces == null || interfaces.length == 0) {//使用cglib代理
            return CglibProxy.newCglibInstance(obj);
        } else {//使用jdk代理
            return InvocationProxy.newInstance(obj);
        }
    }
}

 

package littlehow.proxy.anno;

import littlehow.proxy.chain.Chain;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * BeforeChain
 *
 * @author littlehow
 * @time 2016-09-26 18:22
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface BeforeChain {
    Class[] value();
}






package littlehow.proxy.anno;

import littlehow.proxy.chain.Chain;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * AfterChain
 *
 * @author littlehow
 * @time 2016-09-26 18:26
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface AfterChain {
    Class[] value();
}

 

代理类所依赖的注解(切入方式,前切链,后继链):

package littlehow.proxy.anno;

import littlehow.proxy.enm.CutType;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * Cut
 *
 * @author littlehow
 * @time 2016-09-26 12:59
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Cut {
    CutType value() default CutType.ROUND;
}

 

 

 

 

 

切入类型枚举(前切,后继,环绕):

 

package littlehow.proxy.enm;

/**
 * CutType
 *
 * @author littlehow
 * @time 2016-09-26 12:56
 */
public enum CutType {
    BEFORE(1),//0x0001
    AFTER(2),//0x0002
    ROUND(3);//0x0003
    private int value;
    CutType(int value) {
        this.value = value;
    }

    public int getValue() {
        return this.value;
    }
}

 

 

 

业务链和上下文管理类以及终链:

 

package littlehow.proxy.chain;

/**
 * PreChain
 *
 * @author littlehow
 * @time 2016-09-26 14:06
 */
public abstract class Chain {
    protected Chain next;

    public void setNext(Chain next) {
        this.next = next;
    }

    public Chain(){

    }
    public Context getContext() {
        return ContextManager.get();
    }

    /**
     * 自己的业务过程
     * @return
     */
    public abstract void invoke();

    /**
     * 执行
     */
    public void execute() {
        invoke();
        next();
    }

    /**
     * 下一链
     */
    public void next() {
        if(next != null)
            next.execute();
    }
}






package littlehow.proxy.chain;

import java.lang.reflect.Method;

/**
 * Context  基础上下文
 *
 * @author littlehow
 * @time 2016-09-26 14:35
 */
public class Context {
    /** 切入方法 */
    private Method method;
    /** 方法参数 */
    private Object[] arguments;

    public Context(Method method, Object[] arguments) {
        this.method = method;
        this.arguments = arguments;
    }

    public Method getMethod() {
        return method;
    }

    public Object[] getArguments() {
        return arguments;
    }
}






package littlehow.proxy.chain;

/**
 * ContextManager
 *
 * @author littlehow
 * @time 2016-09-26 14:52
 */
public class ContextManager {
    private static ThreadLocal contextManager = new ThreadLocal<>();

    public static void set(Context context) {
        contextManager.set(context);
    }

    public static Context get() {
        return contextManager.get();
    }

    public static void remove() {
        contextManager.remove();
    }
}






package littlehow.proxy.chain;

/**
 * EndChain
 *
 * @author littlehow
 * @time 2016-09-26 14:58
 */
public class EndChain extends Chain {

    @Override
    public void invoke() {
        ContextManager.remove();//移除上下文
    }
}

 

 

 

一下是测试用例:

 

package littlehow.proxy.test;

import littlehow.proxy.anno.AfterChain;
import littlehow.proxy.anno.BeforeChain;
import littlehow.proxy.anno.Cut;
import littlehow.proxy.enm.CutType;

import javax.annotation.PreDestroy;

/**
 * Bean
 *
 * @author littlehow
 * @time 2016-09-26 09:51
 */
public class Bean {
    @Cut(CutType.ROUND)
    @BeforeChain({TimeChain.class})
    @AfterChain({TimeChain.class})
    public void run() {
        System.out.println("这个使用cglib代理");
    }
}

 

 

 

package littlehow.proxy.test;


import littlehow.proxy.anno.AfterChain;

/**
 * BeanHasInterface
 *
 * @author littlehow
 * @time 2016-09-26 09:49
 */
public final class BeanHasInterface implements MyInter {

    @Override
    @AfterChain(TimeChain.class)
    public void run() {
        System.out.println("这个是用jdk进行代理");
    }
}






package littlehow.proxy.test;

import littlehow.proxy.chain.Chain;

import java.util.concurrent.TimeUnit;

/**
 * DelayChain
 *
 * @author littlehow
 * @time 2016-09-26 18:11
 */
public class DelayChain extends Chain{

    @Override
    public void invoke() {
        try {
            System.out.println("我先睡觉3秒钟");
            TimeUnit.SECONDS.sleep(3);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }
}






package littlehow.proxy.test;


import littlehow.proxy.anno.AfterChain;
import littlehow.proxy.anno.BeforeChain;
import littlehow.proxy.anno.Cut;
import littlehow.proxy.enm.CutType;

/**
 * MyInter
 *
 * @author littlehow
 * @time 2016-09-26 09:49
 */
public interface MyInter {
   @Cut(CutType.ROUND)
   @BeforeChain(TimeChain.class)
   @AfterChain(DelayChain.class)
   void run();
}






package littlehow.proxy.test;

import littlehow.proxy.chain.Chain;

/**
 * TimeChain  测试链,记录调用前的时间
 *
 * @author littlehow
 * @time 2016-09-26 14:27
 */
public class TimeChain extends Chain {

    @Override
    public void invoke() {
        System.out.println("方法名字是:"+this.getContext().getMethod().getName() + ",调用时间为:" + System.currentTimeMillis());
    }
}






package littlehow.proxy.test;

import littlehow.proxy.ProxyUtils;

/**
 * Test
 *
 * @author littlehow
 * @time 2016-09-26 09:51
 */
public class Test {
    @org.junit.Test
    public void cgligTest() {
        Bean bean = new Bean();
        //进行代理
        bean = ProxyUtils.getProxyInstance(bean);
        bean.run();
        //确定是否为cglib动态生成的字节码类
        System.out.println(bean.getClass());//class littlehow.proxy.test.Bean$$EnhancerByCGLIB$$ef9b8cdb
    }

    @org.junit.Test
    public void jdkTest() {
        //这个地方需要用接口的引用来接收代理对象
        MyInter bean = new BeanHasInterface();
        bean = ProxyUtils.getProxyInstance(bean);
        bean.run();
        //确认是否为jdk进行的代理
        System.out.println(bean.getClass());//class com.sun.proxy.$Proxy2
    }
}

 

没有经过大规模测试,后期运用到项目中,会陆续进行测试,所以如果有人能发现问题,请一定要提出,谢谢

你可能感兴趣的:(java)