代理模式之动态代理

1 什么是代理

代理模式: 代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的租房、买房中介。

2 代理模式的分类

静态代理: 我们通常都很熟悉。有一个写好的代理类,实现与要代理的类的一个共同的接口。

动态代理: 其实是一种方便运行时候动态的处理代理方法的调用机制,通过代理可以让调用者和实现者之间解耦,例如RPC调用,对于我们调用者来说我就是想对用远程的那个方法,对于内部寻址啊,序列化反序列化等等这些交给代理来就行了。

3 动态代理

3.1 分类

JDK动态代理

利用拦截器(拦截器必须实现InvocationHanlder)加上反射机制生成一个实现代理接口的匿名类。

在调用具体方法前调用InvokeHandler来处理。

CGLiB动态代理

利用ASM开源包,对代理对象类的class文件加载进来,通过修改其字节码生成子类来处理。

实现CGLIB动态代理必须实现MethodInterceptor(方法拦截器)接口。

二者区别:

JDK只能针对接口不能针对类实现代理。

CGLib通过继承方式实现代理。所以类或方法最好不要声明成final,对于final类或方法,是无法继承的。

Spring如何选择用JDK还是CGLiB?

1)当Bean实现接口时,Spring就会用JDK的动态代理。
2)当Bean没有实现接口时,Spring使用CGlib是实现。
3)可以强制使用CGlib(在spring配置中加入<aop:aspectj-autoproxy proxy-target-class=“true”/>)。

3.2 实现条件

在java中规定,要想产生一个对象的代理对象,那么这个对象必须要有一个接口,所以我们第一步就是设计这个对象的接口,在接口中定义这个对象所具有的行为(方法)。它通过在运行时创建代理类,来适应变化。主要用到的是Reflect中的Proxy和InvocationHandler类。

3.3 应用场景:

当用户要调用一个类的方法时,用户可以通过调用代理,代理通过接口调用原来的类的方法,代理在把方法给用户前可以添加一些方法,如错误日志,用户类的方法运行的时间来监听类方法的性能。当代理完成时候就是当代理调用方法时候,就会启动InvocationHandler里的invoke方法(在测试类中代理类调用方法时有所体现)。

3.4 具体实例

代理类:

import com.danger.user.service.UserInfoService;
import com.danger.user.service.UserInfoServiceImpl;

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

public class LogHander implements InvocationHandler {

    private Object targetObject;

    public Object newProxyInstance(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 {
        System.out.println("start-->>" + method.getName());//方法执行前的操作
        for (int i = 0; i < args.length; i++) {
            System.out.println(args[i]);
        }
        Object ret = null;
        try {
            ret = method.invoke(targetObject, args);
        } catch (Exception e) {
            e.printStackTrace();
            System.out.println("error-->>" + method.getName());//出现异常时的操作
            throw e;
        }
        return ret;
    }

    public static void main(String[] args) throws Exception {
        //代理类
        LogHander logHander = new LogHander();

        //获得代理对象
        UserInfoService userInfoService = (UserInfoService) logHander.newProxyInstance(new UserInfoServiceImpl());

        //调用代理对象的sing方法
        String retValue = userInfoService.sing("冰雨");
        System.out.println(retValue);

        //调用代理对象的dance方法
        String value = userInfoService.dance("江南style");
        System.out.println(value);
    }

}

接口:

public interface UserInfoService {
    /**
     * 唱歌
     * @param name
     * @return
     */
    String sing(String name);

    /**
     * 跳舞
     * @param name
     * @return
     */
    String dance(String name);
}

实现接口的目标对象

import org.springframework.stereotype.Service;

@Service
public class UserInfoServiceImpl implements UserInfoService{
    @Override
    public String sing(String name) {

        return "唱"+name+"歌!好听!";
    }

    @Override
    public String dance(String name) {
        return "跳"+name+"舞!好看!";
    }
}

运行代理类中 的main方法,可以看到如下打印信息:

start-->>sing
冰雨
唱冰雨歌!好听!
start-->>dance
江南style
跳江南style舞!好看!

newProxyInstance 方法用来返回一个代理对象,这个方法总共有3个参数,
ClassLoader loader 用来指明生成代理对象使用哪个类装载器,
Class<?>[] interfaces 用来指明生成哪个对象的代理对象,通过接口指定,
InvocationHandler h 用来指明产生的这个代理对象要做什么事情。
所以我们只需要调用newProxyInstance方法就可以得到某一个对象的代理对象了。

参考: > https://www.cnblogs.com/xnfTosharing/p/11321465.html

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值