java两种代理方式的具体实现

代理是设计模式中一种模式,其目的就是为其他对象提供一个代理以控制对某个对象的访问。

代理类和委托类通常会实现相同的接口,所以在访问者看来两者没有丝毫的区别。通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为实施不同控制策略预留了空间,从而在设计上获得了更大的灵活性

代理分为两种,一种是静态代理,另一种是动态代理。下面分别介绍一些是如何实现的。

1、静态代理

静态代理,创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。

静态代理类与委托类,需要实现同一个接口。

例如,有接口UserManager

public interface UserManager{
    public void addUser(User user);
}

有个具体的实现类,UserManagerImpl:

public class UserManagerImpl implements UserManager{
    
    public void addUser(User user){
        System.out.println("add user");
    }
}

代理类代码如下:

public UserManagerProxy implements UserManager{
    private UserManager userManager;
    public UserManagerProxy(UserManager userManager){
        this.userManager =  userManager;
    }
    
    @Override
    public void addUser(User user){
        System.out.println(" start do some other thing.....");
        userManager.addUser(user);
        System.out.println(" finish do other thing.......");
    }
}

具体使用:

public void test{
    User user = new User();
    UserManager userManager = new UserManagerProxy(new UserManagerImpl());
    userManager.addUser(user);
}

print:
 start do some other thing.....
 add user
 finish do other thing.......
     

静态代理可以对实现类进行统一的管理,如在调用具体实现类之前,需要打印日志等信息,这样我们只需要添加一个代理类,在代理类中添加打印日志的功能,然后调用实现类,这样就避免了修改具体实现类。满足我们所说的开闭原则。但是如果想让每个实现类都添加打印日志的功能的话,就需要添加多个代理类。并且只能代理一种类型。

2、动态代理

动态代理是在程序运行时运用反射机制动态创建而成。

动态代理有两种实现方式,一种是java自带的invocationhandler和第三方cglib,cglib不做详细介绍。

还是以静态代理的代码为例进行说明,UserManager、UserManagerImpl代码参考静态代理中的代码。

Proxy有个静态方法:getProxyClass(ClassLoader,interfaces),我们只要出入类(接口)加载器和其对应的接口(可以是多个),proxy代理类就会返回对应的一个class。

获取到代理的class后,可以调用getConstructor获取对应的Constructor对象。然后再调用该对象的newInstance方法返回对应的对象,该方法需要传递一个InvocationHandler的实现类,在这个实现类中,我们可以做一些我们想做的事情,例如日志输出。

首先看下获取代理类的方法

public Object getProxy(Object target) throws Exception{
    Class proxyClass = Proxy.getProxyClass(target.getClass().getClassLoader,target.getClass().getInerfaces());
Constructor c = proxyClass.getConstructor(InvocationHander.class);
Object proxy = c.newInstance(new InvocationHandler(){
    @Override
    public Object invoke(Object proxy,Mehtod m,Object[] args) throws Exception{
        System.out.println("proxy:start to do some other things.......");
        Object rst = method.invoke(target,args);
        System.out.println("proxy:finish do some other things.......");
        return rst;
    }
});
    return proxy;
}

//另外,获取对应的代理类也可以使用,Proxy.getInstance(ClassLoader,interface[],new InvocationHandler(){});来实现

调用方式:

public void static{
    UserManager uerManager = new UserManagerImpl();
    User user =  new User();
    UserManager proxy = (UserManager)getProxy(userManager);
    proxy.addUser(user);
}

print:
proxy:start to do some other things.......
add user
proxy:finish do some other things.......

如果我们把对外的接口都通过动态代理来实现,那么所有的函数调用最终都会经过invoke函数的转发,因此我们就可以在这里做一些自己想做的操作,比如日志系统、事务、拦截器、权限控制等。这也就是AOP(面向切面编程)的基本原理。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值