java代理模式



·前缘

第一次接触代理模式是在学习《大话设计模式》这本书的时候,代理顾名思义就是创建一个代理类来实现对目标对象的访问控制。提供这个代理类的好处就是可以在实现目标对象功能的前提下,自定义实现方式(比如增加额外的功能操作)可以扩展目标对象的功能。下面先用一张图来说明一下我的思路:


上图中Interface是公共的接口,Proxy是代理类,它实现抽象接口并依赖于目标对象。RealObject也实现了抽象接口。代理模式的关键点在于代理对象与目标对象。代理对象是对目标对象的扩展,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。它主要体现了设计模式的开闭原则:对扩展开发,对修改关闭。怎么理解呢?很简单,我们可以借助代理类来增加一些功能,而不需要修改原有的代码。

·分类

根据具体实现方式的不同代理模式按照代理的创建时期可以分为动态代理和静态代理。

静态代理:

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

动态代理:

在程序运行时,通过反射机制动态创建出来。

·静态代理实例

实现静态代理主要有三步:

1、定义业务接口、业务接口实现类

/**
 * 定义一个业务接口
 * @author guigui
 *
 */
public interface Account {
	//查询
	public void queryAccount();
	//修改
	public void updateAccount();
}
/**
 * 目标类(委托类)
 * @author guigui
 *
 */

public class AccountImpl implements Account{

	@Override
	public void queryAccount() {
		System.out.println("--查询方法--");
	}

	@Override
	public void updateAccount() {
		System.out.println("--修改方法--");
	}

}



2、定义代理类,且实现业务接口;

/**
 * 代理类
 * @author guigui
 *
 */
public class AccountProxy implements Account{
	private AccountImpl accountImpl;
	public AccountProxy(AccountImpl accountImpl){
		this.accountImpl=accountImpl;
	}
	@Override
	public void queryAccount() {
		System.out.println("---查询前---");
		accountImpl.queryAccount();
		System.out.println("---查询后---");
	}
	@Override
	public void updateAccount() {
		System.out.println("---更新前---");
		accountImpl.updateAccount();
		System.out.println("---更新后---");
	}
}


3、客户端调用。

/**
 * 实例化一个调用代理类的客户端
 * @author guigui
 *
 */
public class TestProxy {
	public static void main(String[] args) {
		AccountImpl accountImpl=new AccountImpl();
		AccountProxy accountProxy=new AccountProxy(accountImpl);
		accountProxy.queryAccount();
		accountProxy.updateAccount();
	}
}


至此,实现了静态代理。虽然它做到了在不修改目标对象的功能的前提下,对目标代码进行扩展。但是不难发现,代理对象需要与目标对象实现一样的接口,所以会有很多代理类,还有就是接口方法有修改,目标对象与代理对象都需要维护。

·动态代理实例

动态代理与静态代理的区别在于动态代理不需要实现接口。动态代理类的字节码在程序运行时由java的反射机制动态生成。代理对象的生成是利用JDK的API或者Cglib代理。

··使用JDK的动态代理,使用动态代理的对象必须实现一个或多个接口。

1、代理工厂类(实现InvocationHandler接口)

/**
 * 创建动态代理对象
 * 动态代理不需要实现接口,但是要指定接口类型
 * @author guigui
 *
 */
public class ProxyFactory implements InvocationHandler{
	 private Object target;    
	    /**  
	     * 绑定委托对象并返回一个代理类  
	     * @param target  
	     * @return  
	     */    
	    public Object GetInstance(Object target) {    
	        this.target = target;    
	        //取得代理对象    
	        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);     
	    }    
	    
	    @Override    
	    /**  
	     * 调用方法  
	     */    
	    public Object invoke(Object proxy, Method method, Object[] args)    
	            throws Throwable {    
	        Object result=null;    
	        System.out.println("before");    
	        //执行方法    
	        result=method.invoke(target, args);    
	        System.out.println("after");    
	        return result;    
	    } 
}


2、客户端调用(传入真正的委托类)

/**
 * 测试jdk动态代理类
 * @author guigui
 *
 */
public class JDKProxyTest {
	public static void main(String[] args) {    
        ProxyFactory proxy = new ProxyFactory();    
    // 在这里进行真正的对象传入  
        Account account=(Account)proxy.GetInstance(new AccountImpl());
        account.queryAccount();    
    }    
}


··使用Cglib动态代理,它是在内存中创建一个子类对象从而实现对目标对象功能的扩展。

1、创建ProxyFactory代理类

/**
 * cglib子类代理工厂
 * 对AccountImpl在内存中动态创建一个子类对象
 * @author guigui
 *
 */
public class ProxyFactory implements MethodInterceptor{

	 //维护目标对象
    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }
  //给目标对象创建一个代理对象
    public Object getProxyInstance(){
        //1.工具类
        Enhancer en = new Enhancer();
        //2.设置父类
        en.setSuperclass(target.getClass());
        //3.设置回调函数
        en.setCallback(this);
        //4.创建子类(代理对象)
        return en.create();

    }
	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
		System.out.println("开始事务...");

        //执行目标对象的方法
        Object returnValue = method.invoke(target, args);

        System.out.println("提交事务...");

        return returnValue;
	}


2、客户端测试类

/**
 * cglib代理测试类
 * @author guigui
 *
 */
public class CglibProxyTest {
	public static void main(String[] args) {
		//目标对象
		AccountImpl target=new AccountImpl();
		//代理对象
		AccountImpl proxy=(AccountImpl)new ProxyFactory(target).getProxyInstance();
		proxy.queryAccount();
	}
	
}



Java代理模式是一种结构型设计模式,其目的是为其他对象提供一种代理以控制对这个对象的访问。代理对象可以在客户端和目标对象之间充当中介,以便于客户端访问目标对象时,可以在不改变目标对象的情况下添加一些额外的功能,比如安全性、远程访问、缓存等。 在Java中,代理模式可以通过两种方式实现:静态代理和动态代理。静态代理需要手动编写代理类,而动态代理可以在运行时通过反射机制动态生成代理类,更加灵活。 举个例子,假设我们有一个接口`Subject`,其中定义了一些方法。我们希望在调用这些方法时,增加一些额外的日志记录功能。我们可以编写一个代理类`SubjectProxy`,在代理类中实现接口方法并调用目标对象的方法,同时在方法前后添加日志记录的代码。客户端则通过代理类访问目标对象。 静态代理示例代码如下: ```java public interface Subject { void doSomething(); } public class RealSubject implements Subject { @Override public void doSomething() { System.out.println("RealSubject do something."); } } public class SubjectProxy implements Subject { private Subject realSubject; public SubjectProxy(Subject realSubject) { this.realSubject = realSubject; } @Override public void doSomething() { System.out.println("Before do something."); realSubject.doSomething(); System.out.println("After do something."); } } public class Client { public static void main(String[] args) { Subject realSubject = new RealSubject(); Subject subjectProxy = new SubjectProxy(realSubject); subjectProxy.doSomething(); } } ``` 动态代理示例代码如下: ```java public class SubjectHandler implements InvocationHandler { private Object target; public SubjectHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("Before " + method.getName()); Object result = method.invoke(target, args); System.out.println("After " + method.getName()); return result; } } public class Client { public static void main(String[] args) { Subject realSubject = new RealSubject(); InvocationHandler handler = new SubjectHandler(realSubject); Subject subjectProxy = (Subject) Proxy.newProxyInstance(realSubject.getClass().getClassLoader(), realSubject.getClass().getInterfaces(), handler); subjectProxy.doSomething(); } } ``` 无论是静态代理还是动态代理,代理模式都可以在不改变目标对象的情况下,为其添加额外的功能,提高代码的可复用性和灵活性。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值