java基础--19动态代理

目录

 

1.静态代理

2.JDK动态代理

3.CGLib的方式实现动态代理

 

4.JDK动态代理和CGLib动态代理的区别


1.静态代理

   代理是一个基本的设计模式,代理通常充当着中间人的角色。只要逆向将额外的操作,从实际对象中分离到不同的地方的时候,特别是当你希望很容易的做出修改,从没有额外的操作转为使用这些操作的时候。就用代理。

  先来看一个简单的代理

  先来一个接口

public interface Interface {
    void doSomething();

    void somethingElse(String arg);
}

 再来一个实现类:

public class RealObject implements Interface {
    @Override
    public void doSomething() {
        System.out.println("doSomething");
    }

    @Override
    public void somethingElse(String arg) {
        System.out.println("somethingElse" + arg);
    }
}

  接下来用一个代理类来执行它:

public class SimpleProxy implements Interface {
    private Interface proxied;

    public SimpleProxy(Interface proxied) {
        this.proxied = proxied;
    }

    @Override
    public void doSomething() {
        proxied.doSomething();
        System.out.println("SimpleProxy doSomething");
    }

    @Override
    public void somethingElse(String arg) {
        proxied.somethingElse(arg);
        System.out.println("SimpleProxy " + arg);
    }
}

  测试:

public class SimpleProxyDemo {
    public static void consumer(Interface anInterface){
        anInterface.doSomething();
        anInterface.somethingElse("boom");
    }

    public static void main(String[] args) {
        //consumer(new RealObject());
        consumer(new SimpleProxy(new RealObject()));
    }
}

 结果:

  

 ok,上面是静态代理,缺点是 如果目标类有一百个方法,那么代理类也会有一百个方法,这个样子逻辑会重复很多。 重点是动态代理,因为他能动态的创建代理,并且动态的处理对所代理的方法进行调用。在动态代理上所做的所有调用都会被重定向到单一的调用处理器上。

2.JDK动态代理

    动态代理的实现也分为两类,一类是基于接口的动态代理,一个是基于继承的动态代理,实现的代表就是基于Jdk的动态代理和基于CGLib的动态代理,

   JDK动态代理实现要点:

  

  接口和实现类还是和上面的一样

public class DynamicProxyHandler implements InvocationHandler {
    private Object proxied;

    public DynamicProxyHandler(Object proxied) {
        this.proxied = proxied;
    }

    /**
     * 所又通过动态代理实现的方法,全部使用invoke调用
     *
     * @param proxy
     * @param method
     * @param args
     * @return
     * @throws Throwable
     */
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("prox:" + proxy.getClass() + ",method:" + method + ",args:" + args);
        if (args != null) {
            for (Object arg : args) {
                System.out.println(" " + arg);
            }
        }
        return method.invoke(proxied, args);
    }
}

 

public class SimpleDynamicProxy {
    public static void consumer(Interface anInterface) {
        anInterface.doSomething();
        anInterface.somethingElse("boom");
    }

    public static void main(String[] args) {
        //正常业务调用
        RealObject realObject = new RealObject();
        consumer(realObject);
        //现在擦汗如一个代理的调用链
        Interface interfaces = (Interface) Proxy.newProxyInstance(
                Interface.class.getClassLoader(),
                realObject.getClass().getInterfaces(),
                new DynamicProxyHandler(realObject)
        );
        consumer(interfaces);
    }
}

 

通过调用静态方法的Proxy.newProxyInstance()可以创建动态代理,这个方法需要得到一个类加载器,通常可以从已经被加载的对象中获得类加载器,还需要一个希望该代理实现的接口列表(不是类或者抽象类),以及InvocationHandler接口的一个实现。动态代理会将所有的调用重定向到调用处理器,因此通常会向调用处理器的构造器传递一个实际对象的引用。从而可以使的掉欧阳那个处理器在执行其中介任务时,可以将请求转发。

可以通过传递其他的参数来过滤某些方法的调用:

接口新增一个插入的方法:

当接口新增加方法后,静态代理的话代理类也要实现相应的接口,而动态代理的代理类什么都不用变。

public class MethodSelector implements InvocationHandler {
    private Object object = null;

    MethodSelector(Object object) {
        this.object = object;
    }

    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        if (method.getName().equals("insert"))
            System.out.println("代理正在执行插入的方法");
        return method.invoke(object, args);
    }
}

 

public class SelectMethods {
    public static void main(String[] args) {
        RealObject realObject = new RealObject();
        Interface anInterface = (Interface) Proxy.newProxyInstance(realObject.getClass().getClassLoader(),
                realObject.getClass().getInterfaces(),
                new MethodSelector(realObject)
        );
        anInterface.doSomething();
        anInterface.insert("user");
        anInterface.somethingElse("boom");
    }
}

 结果:

 

 jdk源码解析:

 本质上也就是JDK在运行的时候生成代理的类,java.lang.reflect.Proxy接收多少个接口就会生成多少个代理的类。每个代理的类和静态代理类一样实现了接口的所有的方法。动态生成的代理类属于中间变量的感觉,那我们来看看这个中间的变量示什么样子。

 System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", true);

3.CGLib的方式实现动态代理

 CGLib是基于继承来实现动态代理的。

 包依赖:

   <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>

 实现接口:

 

package com.wx.test1;



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

import java.lang.reflect.Method;

/**
 * User: Mr.Wang
 * Date: 2020/1/27
 */
public class DynamicCGLibHandler implements MethodInterceptor {

    @Override
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before");
        Object re = methodProxy.invokeSuper(o, objects);
        System.out.println("after");
        return re;
    }
}

客户端调用:

public class Test2 {
    public static void main(String[] args) {
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(RealObject.class);
        enhancer.setCallback(new DynamicCGLibHandler());
        Interface anInterface = (Interface) enhancer.create();
        anInterface.doSomething();

    }
}

  结果:

 

4.JDK动态代理和CGLib动态代理的区别

 

练习,使用动态代理实现一个事务管理:

https://blog.csdn.net/qq_41116058/article/details/81942396

https://www.cnblogs.com/caiyao/p/4783417.html

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

时空恋旅人

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值