SpringAOP(二)代理模式:动态代理

SpringAOP(二)代理模式:动态代理

  • 动态代理和静态代理的角色一样
  • 动态代理的代理类是动态生成的,不是我们直接写好的(我们写一个模版,通过模版调用接口自动生成)
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口 — JDK动态代理
    • 基于类:cglib
    • java字节码实现:javasist

需要了解两个类:Proxy:代理,InvocationHandler:调用处理程序

动态代理的好处:

  • 可以使着真实角色的操作更加的纯粹,不用去关注一些公共的业务
  • 公共的就交给代理角色,实现业务的分工
  • 公共业务发生拓展的时候,方便集中管理
  • 一个动态代理类代理的是一个接口,一般就是对应的一类业务
  • 一个动态代理类可以代理多个类,只要实现了同一个接口即可
package com.psy.demo03;

//租房
public interface Rent {
    public void rent();
}
package com.psy.demo03;

//房东(真实角色)
public class Host implements Rent {
    public void rent() {
        System.out.println("房东要出租房子");
    }
}
package com.psy.demo03;

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

//使用这个类自动生成代理类
public class ProxyInvocationHandle implements InvocationHandler {

    //被代理的接口
    private Rent rent;
    public void setRent(Rent rent) {
        this.rent = rent;
    }

    //实现接口的方法(处理代理实例并返回结果)
  // invoke是接口的函数,getProxy的时候传了一个this,里面调用了invoke
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        seeHouse();
        //动态代理的本质,就是使用反射机制实现
        Object invoke = method.invoke(rent, args);
        fare();
        return invoke;
    }

    private void fare() {
        System.out.println("收中介费");
    }

    private void seeHouse() {
        System.out.println("中介带你看房子");
    }

    //生成得到代理类(利用reflect包下的Proxy类去生成)
    public Object getProxy(){
      // invoke是接口的函数,getProxy的时候传了一个this,里面调用了invoke
        Object o = Proxy.newProxyInstance(this.getClass().getClassLoader(), rent.getClass().getInterfaces(), this);
        return o;
    }
}
package com.psy.demo03;
/**
 * 动态代理:
 *      真实角色不是写死的,可以调用多个真实角色(不同接口的)
 * <p>
 *      静态代理只能是一个代理类对应一个接口类,因为静态代理类中使用的真实角色的方法是固定的。
 *          即,如果我传入的其他类型的真实角色中没有rent方法,那么就会报错(没有复用性)。
 * <p>
 *      在实际中,肯定不能只有一个接口(固定传入一个真实角色,),所以需要动态代理(动态的传
 *          入不同类型的真实角色,方法是通过反射实现的,所以不用提前写好方法名(方法名可以不固定))。
 *          方法名不固定+真实角色不固定=代理角色不固定=动态代理(动起来了)
 *      相反,静态代理中真实角色必须是固定的,因为代理角色中掉赢了该角色的方法,所以真实角色需要固定
 */
public class Client {
    public static void main(String[] args) {
        //真实角色
        Host host = new Host();
        //代理角色
        ProxyInvocationHandle proxyInvocationHandle = new ProxyInvocationHandle();
        proxyInvocationHandle.setRent(host);
        Rent proxy = (Rent) proxyInvocationHandle.getProxy();
				// invoke是接口的函数,getProxy的时候传了一个this,里面调用了invoke
        proxy.rent();
    }
}

将动态代理类变成万能的(将被代理的类变成了通用的target,传什么用什么)

package com.psy.demo03;

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

//使用这个类自动生成代理类
public class ProxyInvocationHandle implements InvocationHandler {

    //被代理的接口(将之改造成通用的接口目标类)
    private Object target;
    public void setObject(Object target) {
        this.target = target;
    }

    //实现接口的方法(处理代理实例并返回结果)
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        seeHouse();
        //动态代理的本质,就是使用反射机制实现
        Object invoke = method.invoke(target, args);
        fare();
        return invoke;
    }

    private void fare() {
        System.out.println("收中介费");
    }

    private void seeHouse() {
        System.out.println("中介带你看房子");
    }

    //生成得到代理类(利用reflect包下的Proxy类去生成)
    public Object getProxy(){
        Object o = Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
        return o;
    }
}

总结:

静态代理:
抽象角色:接口或者抽象类(主要是真实角色的行为)
真实角色:实现抽象角色接口
代理角色:代理真实角色,代理角色类中有真实角色类的实例,然后代理角色就能使用真实角色的方法(公共业务),此外还能外加一些其他的方法。
客户端:客户端并不能直接通过真实角色的实例去调用真实角色的方法,只能通过代理角色的实例去调用该方法

动态代理(核心是生成代理角色的类):
角色和静态代理一样。但是代理角色是动态生成的。
那怎么样才能称之为代理呢?
1、抽象角色的方法名不固定
2、真实角色不固定
如何实现上述两个不固定呢?
1、抽象方法不固定
ProxyInvocationHandle(相对于静态代理来说新增的类,此类主要作用是生成代理角色)实现了InvocationHandler接口,该接口有invoke方法,此方法主要是通过反射机制实现抽象角色的方法(该方法主要是在客户端通过代理对象调用,然后Java动态代理会截获方法调用)。就可以实现抽象方法名的不固定。
2、真实角色的不固定
ProxyInvocationHandle中将实例属性从真实角色类改成Object即可,然后在客户端的时候通过set方法进行set就行,这就实现了真实角色的不固定。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值