静态代理与动态代理
代理模式是java开发中用到的相对比较多的设计模式,其中的思想就是主业务和相关业务分离。所谓的代理设计就是指由一个代理主题来操作真实主题,真实主题执行具体的业务操作,而代理主题负责其他相关业务的处理。比如我们在进行删除操作的时候需要检验一下用户是否登陆,我们可以删除看成主业务,而把检验用户是否登陆看成其相关业务,那么这个活动就可以用代理模式来进行处理。
首先我们来看一下静态代理,在使用静态代理时,代理对象和被代理对象实现统一接口,随意在应用代理时首先要编写一个接口:
public interface IHello {
public void sayHello1() ;
public void sayHello2() ;
public void sayHello3() ;
public void sayHello4() ;
}
然后编写代理对象,该类和被代理对象一样实现接口IHello.java,只不过在代理对象中增加需要的服务,
代理类ProxyHello.java代码如下:
package com.spring.test;
/**
*这里使用构造方法来传递实现接口IHello的任意类,而在IHello的几个业务方法中调用的是传递进去的类方法
*,在各个方法中增加相应的服务,这就是前面说的代理。
*/
public class ProxyHello implements IHello {
private IHello hello;
public ProxyHello(IHello hello) {
this.hello = hello;
}
public void validateUser() {
System.out.println("验证用户");
}
public void sayHello1() {
validateUser();
hello.sayHello1();
}
public void sayHello2() {
validateUser();
hello.sayHello2();
}
public void sayHello3() {
validateUser();
hello.sayHello3();
}
public void sayHello4() {
validateUser();
hello.sayHello4();
}
}
然后就是编写被代理类,该类实现IHello接口,代码如下:
package com.spring.test;
public class Hello implements IHello{
public void sayHello1() {
System.out.println("111111111111");
}
public void sayHello2() {
System.out.println("222222222222");
}
public void sayHello3() {
System.out.println("333333333333");
}
public void sayHello4() {
System.out.println("444444444444");
}
}
然后就是测试了:
@Test
public void testHello() {
IHello hello = new ProxyHello(new Hello());
hello.sayHello1();
hello.sayHello2();
hello.sayHello3();
hello.sayHello4();
}
执行结果:
验证用户
111111111111
验证用户
222222222222
验证用户
333333333333
验证用户
444444444444
从上面看来,静态代理其设计方法上就是被代理类Hello只关注与其主业务的具体实现而不用关心其他的业务,将Hello的对象注入到代理类中,然后在进行方法的包装,用这种方式来解耦合,不过很显然在静态代理中我么可以看到,我们要为接口中的每个方式实现一个验证方法,代码量很大,更重要的是加入接口中增加一个方法或者减少一个方法都需要去修改代理类中的代码,很不方便。那么我们就想到了动态代理。
动态代理:
动态代理是根据静态代理机制,抽象出一个泛型代理。他不依赖任何被代理对象的代理实现,该动态代理类需要实现InvocationHandler接口
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
*
* <pre>
* 项目名称:SpringTest
* 类名称:DynamicProxy
* 类描述:
* 创建人:ZDX
* 创建时间:2014年11月22日 上午12:09:44
* 修改人:ZDX
* 修改时间:2014年11月22日 上午12:09:44
* 修改备注:
* @version
* </pre>
*/
public class DynamicProxy implements InvocationHandler {
private Object object;
/**
*
* <pre>
* 方法名称:bind
* 方法描述: 该类的bind()方法中使用Proxy的静态方法
* newProxyInstance建立一个代理对象,该方法中有3个参数,
* 第一个参数是指定代理类的类加载器,
* 第二个参数指定被代理类的实现接口,
* 第三个参数指定方法调用的处理程序,这里即本程序
*
* @version
* </pre>
*/
public Object bind(Object object) {
this.object = object;
return Proxy.newProxyInstance(object.getClass().getClassLoader(),
object.getClass().getInterfaces(), this);
}
/**
* <pre>
* 调用invoke方法会传入被代理对象的方法与参数,
* 也就是说,通过method.invoke(object, args)调用代理类对象中
* 的方法,返回结果也就是代理对象中方法的返回结果。
*
* </pre>
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result = null;
try {
validateUser();
result = method.invoke(object, args);
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public void validateUser() {
System.out.println("验证用户");
}
}
@Test
public void testHello() {
DynamicProxy dynamicProxy=new DynamicProxy();
IHello hello=(IHello) dynamicProxy.bind(new Hello());
hello.sayHello1();
hello.sayHello2();
hello.sayHello3();
hello.sayHello4();
}
通过这两种代理可以看出,原本需要在每个程序中出现的代码片段被提取出来,并将片段用在了任意的程序中而丝毫未修改源程序,这就是AOP思想。被提取出来的片段就是横切关注面,片段中的验证用户的方法被称为横向关注点。在AOP编程中,Aspect通过设定一定的规则在程序中需要的时候介入应用程序,为它们提供服务,在不需要的时候,由于其独立性又可以非常方便的脱离出来。