动态代理

动态代理分为jdk代理和CGLIB代理。
jdk 是接口代理jdk的动态代理调用了Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法。
jdk动态代理
使用动态代理的五大步骤

1.通过实现InvocationHandler接口来自定义自己的InvocationHandler;
2.通过Proxy.getProxyClass获得动态代理类
3.通过反射机制获得代理类的构造方法,方法签名为getConstructor(InvocationHandler.class)
4.通过构造函数获得代理对象并将自定义的InvocationHandler实例对象传为参数传入
5.通过代理对象调用目标方法

简单例子如下。

package jdkproxy;

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

/**
 * @Author: kevin
 * @Date: 2019-03-25
 */
public class JdkProxy {
    public static Object createProxy(final Object targetObj, final CustomAspect customAspect) {
        // 使用JDK的Proxy类为目标类创建代理对象
        return Proxy.newProxyInstance(
                // 目标类使用的类加载器
                targetObj.getClass().getClassLoader(),
                // 目标类实现的接口
                targetObj.getClass().getInterfaces(),
                // 执行处理器,代理我们的业务逻辑
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        // 执行切面方法
                        customAspect.startTransaction();
                        // 具体逻辑代码执行,返回值为方法执行结果
                        Object result = method.invoke(targetObj, args);
                        // 执行切面方法
                        customAspect.endTrasaction();
                        // 返回方法执行结果
                        return result;
                    }
                });
    }
}

package jdkproxy;

/**
 * @Author: kevin
 * @Date: 2019-03-25
 */
public interface UserService {
    void test();
}

package jdkproxy;

/**
 * @Author: kevin
 * @Date: 2019-03-25
 */
public class UserServiceImpl implements UserService {
    @Override
    public void test() {
        System.out.println("userservice test");
    }
}

package jdkproxy;

/**
 * @Author: kevin
 * @Date: 2019-03-25
 */
public class CustomAspect {
    public void startTransaction() {
        System.out.println("I get datasource here and start transaction");
    }

    public void endTrasaction() {
        System.out.println("I get datasource here and end transaction");
    }
}


package jdkproxy;

/**
 * @Author: kevin
 * @Date: 2019-03-25
 */
public class MainProxyJdk {
    public static void main(String[] args) {
        System.out.println("before Proxy......");
        UserService userService = new UserServiceImpl();
        userService.test();
        System.out.println("After Proxy......");
        UserService proxyUserService = (UserService)JdkProxy.createProxy(userService, new CustomAspect());
        proxyUserService.test();
    }
}

以上是jdk代理的简单例子。
jdk动态代理:代理类与委托类实现同一接口,主要是通过代理类实现InvocationHandler并重写invoke方法来进行动态代理的,在invoke方法中将对方法进行增强处理。
优点:不需要硬编码接口,代码复用率高。
缺点:只能够代理实现了接口的委托类。
特点:底层使用反射机制进行方法的调用。

CGLIB代理是代理类。
CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。

package cglib;

/**
 * @Author: kevin
 * @Date: 2019-03-25
 */
public class Dao {
    public void test() {
        System.out.println("dao test");
    }
}

package cglib;

import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * @Author: kevin
 * @Date: 2019-03-25
 */
public class DaoProxy implements MethodInterceptor {
    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println(method.getName() + "-before-");
        Object o1 = null;
        try {
            o1 = methodProxy.invokeSuper(o, objects);
        } catch (Exception e) {
            e.printStackTrace();
//            System.out.println(o + "-" + method.getName() + "-" + objects);
        }

        System.out.println(method.getName() + "-after");
        return o1;
    }
}

package cglib;

public interface IMain {
}

package cglib;

import net.sf.cglib.proxy.Enhancer;

/**
 * @Author: kevin
 * @Date: 2019-03-25
 */
public class Main implements IMain {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(Dao.class);
        enhancer.setCallback(new DaoProxy());
        Dao dao = (Dao) enhancer.create();
        dao.test();
    }
}

以上是CGLIB动态代理的简单例子。

实现CGLIB动态代理必须实现MethodInterceptor(方法拦截器)接口。
这个接口只有一个intercept()方法,这个方法有4个参数:

1)obj表示增强的对象,即实现这个接口类的一个对象;
2)method表示要被拦截的方法;
3)args表示要被拦截方法的参数;
4)proxy表示要触发父类的方法对象;

CGLIB:代理类将委托类作为自己的父类并为其中的非final委托方法创建两个方法,一个是与委托方法签名相同的方法,它在方法中会通过super调用委托方法;另一个是代理类独有的方法。在代理方法中,它会判断是否存在实现了MethodInterceptor接口的对象,若存在则将调用intercept方法对委托方法进行代理
优点:可以在运行时对类或者是接口进行增强操作,且委托类无需实现接口。
缺点:不能对final类以及final方法进行代理。
特点:底层将方法全部存入一个数组中,通过数组索引直接进行方法调用。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值