动态代理之java详解

在这里插入图片描述

前言


今天在看spring事务时又想起动态代理,因此便写下这篇文章来和大家交流。动态代理在spring中可谓是十分常见,到处都有他的身影,例如spring中的核心技术aop、spring的事务,以及注解都用到了动态代理,因此但凡你想深入学习spring框架,那么动态代理是必须知道的。


提示:这里可以添加本文要记录的大概内容:
例如:随着人工智能的不断发展,机器学习这门技术也越来越重要,很多人都开启了学习机器学习,本文就介绍了机器学习的基础内容。


提示:以下是本篇文章正文内容,下面案例可供参考

一、什么是代理?

在这里插入图片描述

委托类(目标类) 提供一种代理类以控制对这个委托类的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。用来间接实现委托类并为委托类增加功能,提高扩展性。

1.小试牛刀之静态代理

在学习动态代理之前我们看一下静态代理。使用静态代理我们对上述的概念进行解释

所谓静态也就是在程序运行前就确定了代理类和委托类之间的关系

需求一:为已经实现的方法添加功能

//定义一个接口
public interface Service{
   public void say(String s);
}
//定义第一个实现类
public class ServiceA implements Service{
   @Override
   public void say(String s){
   System.out.println("ServiceA说"+s);
   }
}
//定义第二个实现类
public class SerivceB implements Service{
    @Override
    public void say(String s){
    System.out.println("ServiceB说"+s);
    }
}

现在创建一个代理类来进行对委托类进行功能的加强

public class MyProxy implements Service {
    //定义接口
    private Service service;
    //通过构造方法进行传参来使用委托类的实现方法
    public  MyProxy(Service service){
        this.service = service;
    }
    //这里打印一句话来代表添加的方法
    @Override
    public void say(String s) {
        System.out.println("===加强功能===");
        service.say(s);
    }
}
---------------测试-----------------
@Test
public void show(){
    //面向接口编程
    Service service1 = (Service)new MyProxy(new ServiceA());
    service1.say("你好");
    Service service2 = (Service)new MyProxy(new ServiceB());
    service2.say("谢谢");
}

结果:
在这里插入图片描述
我们可以看出现在我们在调用目标类时不是直接调用的,而是采用代理去间接调用的,这样我们就可以在代理类中添加各种各样的方法,来拓展目标类的功能。

缺点:①一个接口要编写一个代理类,代码可重用性较低②代码冗余

二、动态代理

在这里插入图片描述

动态代理的两种实现:
①: jdk动态代理
②: cglib代理


1.jdk动态代理

提醒:jdk动态代理只能为接口创建代理

1.1常用API

jdk动态代理中用到的两个类

java.lang.reflect.Proxy
java.lang.reflect.InvocationHandler

Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
InvocationHandler 代理实例的调用处理程序实现的接口。每个代理实例都具有一个关联的调用处理程序


常用的方法:
getProxyClass

Class<?>  getProxyClass(ClassLoader loader,Class<?>... interfaces)

为指定接口创建代理类,返回代理类的Class对象
loader:代理类的类加载器
interface:实现的接口的Class对象


isProxy

boolean  Proxy.isProxyClass(Class<?> c);

判断一个类是否为代理类


newProxyInstance

Object   Proxy.newProxyInstance(ClassLoader loader,Class<?>[] interfaces, InvocationHandler h);

生成代理类对象
Invlcationhandler:当对象调用方法的时候会执行Invocationhandler中的方法

Object   invoke(Object proxy, Method method, Object[] args)

getInvocationHandler

InvocationHandler getInvocationHandler(Object proxy)

获取代理类的InvocationHandler

1.2 创建代理:方式一

//定义一个接口
public interface Service {
    void s1();
    void s2();
}
//测试
public void show(){
        //创建接口的代理类
        Class<Service> proxyClass = (Class<Service>) Proxy.getProxyClass(Service.class.getClassLoader(), Service.class);
        //调用方法
        InvocationHandler invocation = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("代理"+method.getName());
                return null;
            }
        };
        //创建代理类对象,利用反射技术进行创建对象
        //使用其调用处理器程序,创建代理类的实例
        Service service = proxyClass.getConstructor(InvocationHandler.class).newInstance(invocation);
        service.s1();
        service.s2();
    }
//执行结果
//代理s1
//代理s2   

1.3 创建代理:方式二

方式二相对方式一简单一点:

    @Test
    public void proxyImpl()throws Exception{
        //创建代理类的处理器
        InvocationHandler invocationHandler = new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("代理2"+method.getName());
                return null;
            }
        };
        //使用newProxyInstance创建代理类的对象
        Service service = (Service)Proxy.newProxyInstance(Service.class.getClassLoader(), new Class[]{Service.class}, invocationHandler);
        //执行方法
        service.s2();
        service.s1();
    }
//执行结果:
//代理2s1
//代理2s2

1.3 自定义代理工厂

我们可以自定义一个代理工厂用来生成代理类对象

//定义一个工厂类实现InvocationHandler接口
public class ProxyFactory implements InvocationHandler {
   //委托类对象
   private Object targetObject;
   //返回代理类对象
   public Object createProxyInstance(Object targetObject){
        //通过构造方法进行传递
        this.targetObject=targetObject;
        return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
targetObject.getClass().getInterfaces(),this);
}
       @Override
      public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result=null;
       try {
       //定义前置通知
      //回调目标类中的方法
     result=method.invoke(targetObject,args);
     //.... 后置通知
      } catch (Exception e) {
            e.printStackTrace();
        //异常通知
     }finally{
        //最终通知
      }
     return result;
     }
}

测试数据准备:

//定义一个接口
public interface Service {
    void s1();
    void s2();
}
//定义一个实现类
public class ServiceA implements Service {
    @Override
    public void s1() {
        System.out.println("s1执行");
    }
    @Override
    public void s2() {
        System.out.println("s2执行");
    }
}

测试:

    @Test
    public void sh(){
        //创建委托类对象
        ServiceA serviceA = new ServiceA();
        Service service = (Service) new ProxyFactory().createProxyInstance(serviceA);
        service.s1();
        service.s2();
    }
//执行结果
//s1执行
//s2执行

注意:jdk实现的代理只能为接口创建代理

2.cglib代理

cglib代理:强大的高性能的字节码生成类库。用于在运行时拓展java类和实现接口。本质是通过动态的生成一个子类去覆盖委托类,并可以拦截委托类以及其父类中除private修饰的方法
最常用的一个类

Enhancer:翻译就是增强剂

引入依赖

<!--cglib依赖-->
<dependency>
   <groupId>cglib</groupId>
   <artifactId>cglib</artifactId>
  <version>2.2.2</version>
</dependency>

了解一下回调函数接口:

在这里插入图片描述

2.1拦截所有方法 MethodInterceptor

//定义一个类当作委托类
public class Person {
    //定义两个方法
    public void say(){
        System.out.println("hello");
    }
    public void eat(){
        System.out.println("吃东西");
    }
}

测试MethodInterceptor

 @Test
    public void show1(){
        //创建Enhancer对象
        Enhancer enhancer = new Enhancer();
        //设置代理类的父类
        enhancer.setSuperclass(Person.class);
        //设置回调MethodInterceptor
        enhancer.setCallback(new MethodInterceptor() {
            @Override
            public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                System.out.println("==拦截方法");
                //methosProxy表示方法对象,o就是代理对象,objects方法参数
                //调用委托类中的方法
                Object o1 = methodProxy.invokeSuper(o, objects);
                return o1;
            }
        });
        //创建代理类对象
        Person person  = (Person) enhancer.create();
        person.eat();
        System.out.println(person.play());

结果:
在这里插入图片描述
补充:

public class Person {
    //定义两个方法
    public void say(){
        this.eat();
        System.out.println("hello");
    }
    public void eat(){
        System.out.println("吃东西");
    }
}

此时只调用say方法的话,也会对eat方法进行拦截,因为say的调用。


2.2拦截有返回值的方法并返回固定值FixedValue

注意:①要拦截的方法一定是有返回值类型的,此时调用没有返回值类型的方法是不执行的②:返回的固定值要确保可以转化为方法的返回值类型防止类型转换异常。
案例:

public class Person {
    public String get01(){
        return "这是get01";
    }
    public int get02(){
        return 99;
    }
}        
    @Test
    public void show1(){
     //创建Enhancer对象
  Enhancer enhancer = new Enhancer();
    //设置代理类的父类
  enhancer.setSuperclass(Person.class);
  enhancer.setCallback(new FixedValue() {
     @Override
      public Object loadObject() throws Exception {
         return "拦截到方法并返回一个固定值";
     }
  });
  //创建代理类对象
   Person person  = (Person) enhancer.create();
   System.out.println(person.get01());
    System.out.println(person.get02());
  }

结果:
在这里插入图片描述

2.3 NoOp不做任何拦截

这个和没使用代理的感觉差不多,简单看一下就可以了

//这个和没使用代理直接创建对象的效果是一致的
@Test
public void show(){
 //创建Enhancer对象
 Enhancer enhancer = new Enhancer();
 //设置代理类的父类
 enhancer.setSuperclass(Person.class);
 //设置回调函数
 enhancer.setCallback(new NoOp() {
 });
 //创建代理类
 Person person = (Person)enhancer.creat();
 person.eat();
 }
 //执行结果:
 //吃东西

2.4不同的方法使用不同的拦截器

案例需求:一个类中的insert开头的方法进行拦截添加一个功能,get开头的方法进行拦截返回固定值

public class Service {

    public void insert1(){
        System.out.println("This is insert1 method");
    }
    public void insert2(){
        System.out.println("This is insert2 method");
    }
    public String get1(){
        return "get1 method";
    }
    public String get2(){
        return "get2 method";
    }
}
方式1
    @Test
    public void show1(){
        //创建Enhancer对象
        Enhancer enhancer = new Enhancer();
        //设置代理类的父类
        enhancer.setSuperclass(Service.class);
        //创建两个回调函数
        Callback[] callbacks = {
            //第一个用来拦截insert方法
            new MethodInterceptor() {
                @Override
                public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
                    System.out.println("拦截到insert开头的方法并添加了一个功能");
                    Object o1 = methodProxy.invokeSuper(o, objects);
                    return o1;
                }
            },
            //第二个方法用来拦截所有的get开头的方法
                new FixedValue() {
                    @Override
                    public Object loadObject() throws Exception {
                        return "固定值";
                    }
                }

        };
        //设置回调函数为数组
        enhancer.setCallbacks(callbacks);
        //设置过滤器用来判断调用不同的方法执行不同的回调函数
        enhancer.setCallbackFilter(new CallbackFilter() {
            @Override
            public int accept(Method method) {
                String s = method.getName();
                //以insert开头的方法就使用第一个回调函数反之第二个
                return s.startsWith("insert")?0:1;
            }
        });
        Service service = (Service)enhancer.create();
        service.insert1();
        service.insert2();
        System.out.println(service.get1());
        System.out.println(service.get2());
    }

结果:
在这里插入图片描述

方式2
    public void show2(){
     //创建Enhancer对象
     Enhancer enhancer = new Enhancer();
     //设置第一个回掉函数
     Callback callback = (MethodInterceptor)(Object o, Method method, Object[] objects, MethodProxy methodProxy)->{
              System.out.println("功能加强");
             return methodProxy.invokeSuper(o,objects);
         };
     //设置第二个回调函数
     Callback callback2 = (FixedValue)()->"固定值";
     //使用CallbackHelper进行筛选
     CallbackHelper callbackHelper = new CallbackHelper(Service.class,null) {
     //设置根据方法设置回调函数
         @Override
         protected Object getCallback(Method method) {
             return method.getName().startsWith("insert") ?callback:callback2;
         }
     };
        //设置父类
        enhancer.setSuperclass(Service.class);
        //调用传递数组
        enhancer.setCallbacks(callbackHelper.getCallbacks());
        //设置回调函数
        enhancer.setCallbackFilter(callbackHelper);
        //获取类的代理对象
        Service  service = (Service) enhancer.create();
        service.insert1();
        service.insert2();
        System.out.println(service.get1());
        System.out.println(service.get2());
    }

结果:
在这里插入图片描述

2.5自定义代理类工厂

//定义一个工厂用来生成类的代理对象
public class CglibFactory implements InvocationHandler {
    //委托类->目标类
    private Object targetObject;
    //传递目标对象
   public Object createProxyInstance(Object targetObject){
       this.targetObject=targetObject;
      Enhancer enhancer=new Enhancer();
    //设置代理类的父类
      enhancer.setSuperclass(targetObject.getClass());
    //设置回调方法
    enhancer.setCallback(this);
    //创建代理类对象
    return enhancer.create();
}
     @Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
      Object result=null;
try{
//前置通知
//回调目标类
result=method.invoke(targetObject,objects);
//后置通知
}catch(Exception e){
e.printStackTrace();
//异常通知
}finally{
//最终通知
}
return result;
}
}

总结

jdk动态代理只能对接口进行代理,不能对普通类进行代理。cglib可以对普通类进行代理(私有除外)

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值