什么是动态代理?Spring中有哪几种实现?有什么区别?

什么是动态代理?Spring中有哪几种实现?有什么区别?

答: 1. 可以任意的控制任意对象的执行过程,这个对象的执行过程可以由客户端灵活的指定
    2. 两种
    3. jdk和CGLib

JDK
	1. JDK version <= 1.6 的时候实现InvocationHandler,重写invoke,自定义初始化对象(method.invoke(Object,args))
	2.利用拦截器(必须要实现InvocationHandler接口)加上反射机制生成一个代理接口的匿名类,在具体方法前调用InvocationHandler来处理

CGlib
	1.实现MethodInterceptor 重写intercept (methodProxy.invokeSuper(Object,args))
	2.CGLib利用ASM框架,对代理对象生成的class文件加载进来,通过修改其字节码文件生成子类来处理
	2.CGLib不能对声明final的类和方法进行代理,因为CGlib原理是动态生成被代理类的子类
	3.完全不受代理类必须实现接口类的限制,采用的是接口继承的方式

JDK默认提供的代理例子:

接口(inteface)

public interface JdkHello {

    public String hello();

    public String world();
}

正常实现类(class)

/**
 * @author youshang
 */
public class JdkHelloImpl implements JdkHello {
    
    @Override
    public String hello() {
        return "hello";
    }
    @Override
    public String world() {
        return "world";
    }
}

代理实现类(Proxy Class)

@Log4j2
public class JdkHelloProxy implements JdkHello {
    
    private JdkHello jdkHello = new JdkHelloImpl();
    
    @Override
    public String hello() {
        log.info("通过动态代理执行hello");
        return jdkHello.hello();
    }

    @Override
    public final String world() {
        log.info("通过动态代理执行world");
        return jdkHello.world();
    }
}

代理类(Proxy)

/**
 * JDK1.6+ 底层提供的动态代理
 */
@Log4j2
public class JdkProxy {

    private Object object;

    public JdkProxy(Object object){
        this.object = object;
    }

    /**
     * 封装代理方法,取代实现InvocationHandler
     * @return
     */
    public Object getProxyInstance() {
        long startTime = System.currentTimeMillis();
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), (proxy, method, args) -> {
            DateTime startDate = DateUtil.date(startTime);
            log.info(String.format("开始操作你的需求: %s ",startDate));
            //进行代理
            Object invoke = method.invoke(object, args);

            long endTime = System.currentTimeMillis();
            log.info(String.format("操作此需求总共耗时: %s 毫秒",(endTime- startTime)));

            return invoke;
        });
    }

//    (proxy, method ,args) -> method.invoke(proxy,args)
//    =
//    new InvocationHandler() {
//        @Override
//        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//            return method.invoke(object,args);
//        }
}

代理类(Proxy)

/**
 * JDK1.6+ 底层提供的动态代理
 */
@Log4j2
public class JdkProxy {

    private Object object;

    public JdkProxy(Object object){
        this.object = object;
    }

    /**
     * 封装代理方法,取代实现InvocationHandler
     * @return
     */
    public Object getProxyInstance() {
        long startTime = System.currentTimeMillis();
        return Proxy.newProxyInstance(object.getClass().getClassLoader(), object.getClass().getInterfaces(), (proxy, method, args) -> {
            DateTime startDate = DateUtil.date(startTime);
            log.info(String.format("开始操作你的需求: %s ",startDate));
            //进行代理
            Object invoke = method.invoke(object, args);

            long endTime = System.currentTimeMillis();
            log.info(String.format("操作此需求总共耗时: %s 毫秒",(endTime- startTime)));

            return invoke;
        });
    }

//    (proxy, method ,args) -> method.invoke(proxy,args)
//    =
//    new InvocationHandler() {
//        @Override
//        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//            return method.invoke(object,args);
//        }
}

测试代理类(Test)

/**
 * 测试jdk动态代理
 */
public class JdkProxyTest {

    @Test
    public void test(){
        //通过代理类实现调用JdkHelloImpl实现类
        JdkHello jdkHello = new JdkHelloProxy();
        //执行代理操作
        JdkHello jdkHelloProxy = (JdkHello)new JdkProxy(jdkHello).getProxyInstance();
        System.out.println(jdkHelloProxy.hello());

        //经过final修饰的方法
        System.out.println(jdkHelloProxy.world());
    }
}

CGLib代理测试例子

代理目标类(class)

public class CglibServiceImpl{
    public String say() {
        return "say";
    }

    public String useCase() {
        return "useCase";
    }

    /**
     * final修饰的方法,CGLib不能代理
     * @return
     */
    public final String example(){
        return "劳资的东西你别碰。。。";
    }
}

代理类(Proxy Class)

/**
 * 实现CGLib核心接口 MethodInterceptor
 */
@Log4j2
public class CglibProxy implements MethodInterceptor {

    private Long startTime;

    public CglibProxy(){
        startTime = System.currentTimeMillis();
    }

    /**
     * 回调接口的方法
     * 回调接口的方法执行的条件是:代理对象执行目标方法时会调用回调接口的方法
     * @param obj
     * @param method
     * @param args
     * @param proxy
     * @return
     * @throws Throwable
     */
    @Override
    public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
        log.info(String.format("方法名: %s",method.getName()));
        log.info(String.format("开始执行日期: %s ", DateUtil.date(startTime)));

        Object o = proxy.invokeSuper(obj, args);

        long endTime = System.currentTimeMillis();
        log.info(String.format("方法总共执行时间: %s 毫秒",endTime - startTime));
        return o;
    }
}

测试CGlib代理方法

    @Test
    public void test(){
        Enhancer enhancer = new Enhancer();
        //将目标类设置为父类,cglib动态代理增强的原理就是子类增强父类,cglib不能增强目标类为final的类和方法
        enhancer.setSuperclass(CglibServiceImpl.class);
        //设置当前类的具体子类(允许为null)
        enhancer.setClassLoader(CglibServiceImpl.class.getClassLoader());
        //设置回调接口,这里的MethodInterceptor实现类回调接口,而我们又实现了MethodInterceptor
        enhancer.setCallback(new CglibProxy());
        //create()方法用于创建cglib动态代理对象
        CglibServiceImpl cglibService = (CglibServiceImpl)enhancer.create();
        //实现CGLib代理调用方法
        System.out.println(cglibService.say());
        System.out.println(cglibService.useCase());
        //通过final修饰的方法,CGlib没办法代理
        System.out.println(cglibService.example());

    }

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值