Welcome everyone

绕不开的动态代理

java 汪明鑫 803浏览 0评论

谈到代理模式,绕不开静态代理、动态代理

谈到动态代理绕不开jdk方式和cglib方式

自然而言也就想到了spring aop的实现就是用了动态代理

AOP编程中如何选择代理模式:

  1. 目标对象需要实现接口,用JDK代理
  2. 目标对象不需要实现接口,用Cglib代理

还有mybatis mapper 生成接口的代理同样用了动态代理

 

jdk方式

核心类:

java.lang.reflect.InvocationHandler

核心方法:

java.lang.reflect.Proxy#newProxyInstance

 

上代码

/**
 * @author wmx
 * @date 2019-09-04
 */
public class ProxyDemo {
    public static void main (String[] args) {
        HelloImpl hello = new HelloImpl();
        MyInvocationHandler handler = new MyInvocationHandler(hello);
        // 构造代码实例
        Hello proxyHello = (Hello) Proxy.newProxyInstance(HelloImpl.class.getClassLoader(), HelloImpl.class.getInterfaces(), handler);
        // 调用代理方法t
        proxyHello.sayHello();
    }
}

interface Hello {
    void sayHello();
}

class HelloImpl implements Hello {
    @Override
    public void sayHello() {
        System.out.println("Hello World");
    }
}

class MyInvocationHandler implements InvocationHandler {
    private Object target;
    public MyInvocationHandler(Object target) {
        this.target = target;
    }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args)
            throws Throwable {
        //写自己包裹代理方法的一些操作
        System.out.println("before invoking sayHello");
        Object result = method.invoke(target, args);
        System.out.println("after invoking sayHello");
        return result;
    }
}

输出:

before invoking sayHello
Hello World
after invoking sayHello

 

小结:

代理者要实现InvocationHandler接口,实现invoke方法

invoke方法就是调用被代理者的方法,然后可以做一些增强,

代理者要持有被代理者的一个引用,

这里涉及到反射的一些知识,反射的知识也是必须要熟悉的

 

这种实现仍然有局限性,因为它是以接口为中心的,相当于添加了一种对于被调用者没有太大意义的限制。

代码简单

 

 

cglib方式

需要引入一个依赖:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-aop</artifactId>
      <version>5.1.9.RELEASE</version>
    </dependency>

 

核心类:

Enhancer

 

/**
 * @author wmx
 * @date 2019-09-04
 */
public class CglibDemo {

    public static void main(String[] args) {
        SayHello proxy = (SayHello) getProxy(new SayHello());
        proxy.sayHello("xinye");

    }

    public static Object  getProxy(SayHello target){
        // 创建增强器  底层是二进制码实现
        Enhancer enhancer = new Enhancer();

        enhancer.setInterfaces(target.getClass().getInterfaces());

        //注意:cglib创建的代理对象都是目标对象的子类
        enhancer.setSuperclass(target.getClass());

        enhancer.setCallback(new MethodInterceptor() {

            @Override
            public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {

                System.out.println("before invoke");
                Object result = method.invoke(target,args);
                System.out.println("after invoke");

                return result;
            }
        });

        return enhancer.create();

    }
}


class SayHello {
    public void sayHello(String msg) {
        System.out.println("Hello World "+msg);
    }
}

输出:

before invoke
Hello World xinye
after invoke

 

小结:

比较JDK proxy,cglib克服对接口的依赖

cglib动态代理采取的是创建目标类的子类的方式,因为是子类化,我们可以达到近似使用被调用者本身的效果。

性能稍高

Cglib包的底层是通过使用字节码处理框架ASM来转换字节码并生成新的类,这一个也是面试经常爱问的

转载请注明:汪明鑫的个人博客 » 绕不开的动态代理

喜欢 (0)

说点什么

您将是第一位评论人!

提醒
avatar
wpDiscuz