Spring动态代理

Posted 明渃筱曦

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring动态代理相关的知识,希望对你有一定的参考价值。

在上一篇博客中简单写了一下静态代理,这里主要讲一下动态代理

动态代理主要有两种

JDK动态代理   CGLIB动态代理

那这两种代理有什么区别呢?

(根据自己的理解总结)

1.JDK动态代理

他的特点是:目标对象必须有接口

他的实质是:创建了接口的一个实现类

他运行的时机:程序运行时

2.CGLIB动态代理

他的特点是:在一个类型没有接口的情况下进行代理

他的实质是:在内存中构建目标类型的子类

他运行的时机是:编译时

简单介绍完这两种代理后,就用个例子具体看怎么实现动态代理

 

 

先做JDK动态代理

准备一个接口ISomeService,接口中有一个方法doSome(),和一个这个接口的实现类SomeServiceImpl,并重写其中的方法,具体代码如下

package demo15;

/**
 * Created by mycom on 2018/3/8.
 */
public interface ISomeService
{
    public void doSome();
}
package demo15;

/**
 * Created by mycom on 2018/3/8.
 */
public class SomeServiceImpl implements ISomeService {
    public void doSome() {
        System.out.println("十点十分的复习");
    }
}

使用JDK动态代理不需要再配置文件中进行配置,所以现在直接进行测试,但是测试的时候不能使用单测,而是使用main方法进行测试

package demo15;

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

/**
 * Created by mycom on 2018/3/8.
 */
public class Test {
    public static void main(String[] args) {
        //首先创建一个接口的实现类
        final SomeServiceImpl service=new SomeServiceImpl();
        //在调用方法之前想使用动态代理记录一下日志,生成动态代理,返回的是接口
        ISomeService proxyInstance =(ISomeService) Proxy.newProxyInstance(service.getClass().getClassLoader(),
                service.getClass().getInterfaces(), new InvocationHandler() {
                    /**
                     *
                     * @param proxy  代理对象
                     * @param method  目标类型的方法
                     * @param args  方法的参数
                     * @return
                     * @throws Throwable
                     */
                    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                        //在这里记录一下日志
                        System.out.println("before=====");
                        //调用method 的
                        method.invoke(service,args);//相当于执行目标类型的方法
                        System.out.println("after=======");
                        return null;
                    }
                });

        //调用动态代理中的方法中的方法
        proxyInstance.doSome();
    }
}

运行的结果如下

这说明运行时先执行了invoke方法,再执行接口中doSome的方法,实验成功!

 

 

使用CGLIB动态代理实现上述中的运行结果,如何实现呢?

这时就不用再创建接口了,(在这里我就使用上面的SomeServiceImpl这个类了,这个类中不用做改动),我直接进行测试了,测试还和上面一样,使用main方法测试,不用配置文件

package demo09;


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

import java.lang.reflect.Method;

/**
 * Created by mycom on 2018/3/8.
 */
public class Test {
    public static void main(String[] args) {
        final SomeServiceImpl service=new SomeServiceImpl();
        Enhancer enhancer=new Enhancer();
        enhancer.setSuperclass(service.getClass());
        enhancer.setCallback(new MethodInterceptor() {
            /**
             *
             * @param o 代理对象
             * @param method 目标类型的方法
             * @param objects 目标方法的参数
             * @param methodProxy 代理类的方法   是一个新的参数
             * @return
             * @throws Throwable
             */
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("before=====");
                methodProxy.invoke(service,objects);
                System.out.println("after=====");
                return null;
            }
        });
        SomeServiceImpl proxy =(SomeServiceImpl) enhancer.create();
        proxy.doSome();
    }
}

运行结果和上面的一样,这就是两种方法实现动态代理!

 

以上是关于Spring动态代理的主要内容,如果未能解决你的问题,请参考以下文章

详解 spring AOP 动态代理

Spring5学习笔记 — “Spring AOP底层原理(动态代理)”

Spring5学习笔记 — “Spring AOP底层原理(动态代理)”

Spring_AOP的实现机制-动态代理

Spring的AOP总结

Spring之静态/动态代理模式