代理模式的定义:
为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
模式结构:
优点:
职责清晰:真实角色只需实现实际的业务逻辑,不需关心其非本职的事务,通过后期的代理完成其他事务,附带结果就是编程简洁清晰。
在程序设计中有一个类的单一性原则问题,这个原则很简单,就是每个类的功能尽可能单一。为什么要单一,因为只有功能单一这个类被改动的可能性才会最小,如果你将其它事务放在真实角色类里面,真实角色类就既要负责自己本身业务逻辑、又要负责其它事务,那么就有两个导致该类变化的原因,如果其它事务规则一旦变化,这个类就必需得改,显然这不是一个好的设计。
代理角色就是客户端和真是角色间的中间层,起到了保护真实角色的作用。
高扩展性
静态代理:
/**
* 定义一个账户接口
*
* @author Administrator
*
*/
public interface Count {
// 查看账户方法
public void queryCount();
// 修改账户方法
public void updateCount();
}<span style="font-family: Arial, Helvetica, sans-serif; font-size: 12px;"> </span>
<pre name="code" class="java">
/**
* 真实类(实际业务逻辑)
*
* @author Administrator
*
*/
public class CountImpl implements Count {
@Override
public void queryCount() {
System.out.println("查看账户方法...");
}
@Override
public void updateCount() {
System.out.println("修改账户方法...");
}
}
/**
* 代理类(增强CountImpl实现类、处理其它事务)
*
* @author Administrator
*
*/
public class CountProxy implements Count {
private CountImpl countImpl;
/**
* 覆盖默认构造器
*
* @param countImpl
*/
public CountProxy(CountImpl countImpl) {
this.countImpl = countImpl;
}
@Override
public void queryCount() {
System.out.println("事务处理之前");
// 调用委托类的方法;
countImpl.queryCount();
System.out.println("事务处理之后");
}
@Override
public void updateCount() {
System.out.println("事务处理之前");
// 调用委托类的方法;
countImpl.updateCount();
System.out.println("事务处理之后");
}
}
<pre name="code" class="java">/**
*测试Count类
*
* @author Administrator
*
*/
public class TestCount {
public static void main(String[] args) {
CountImpl countImpl = new CountImpl();
CountProxy countProxy = new CountProxy(countImpl);
countProxy.updateCount();
countProxy.queryCount();
}
}
动态代理:
动态代理是指无需手工编写代理类,程序在运行时会自动生成代理类(即如静态代理中程序员手工编写的代理类)。
使用JDK的动态代理时主要涉及java.lang.reflect包中的接口InvocationHandler和类Proxy,具体步骤如下:
首先,使用者需实现接口InvocationHandler中的invoke方法,在此方法中编写处理其它事务的代码、并用invoke方式触发真实类中的方法。
接着,Proxy类中提供了newProxyInstance方法动态生成代理类。它会声称实现了真实类所实现的接口,并根据InvocationHandler接口中invoke方法的代码动态生成接口所实现的方法的信息,这样就生成了代理类的Class对象信息。并根据代理类的Class信息生成代理类的对象,返回给使用者。
最后,使用者使用代理类对象,像静态代理一样调用相关方法。
<pre name="code" class="java">/**
* JDK动态代理代理类
*
* @author student
*
*/
public class BookFacadeProxy implements InvocationHandler {
private Object target;
/**
* 绑定委托对象并返回一个代理类
* @param target
* @return
*/
public Object bind(Object target) {
this.target = target;
//取得代理对象
return Proxy.newProxyInstance(target.getClass().getClassLoader(),
target.getClass().getInterfaces(), this); //要绑定接口(这是一个缺陷,cglib弥补了这一缺陷)
}
@Override
/**
* 调用方法
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
Object result=null;
System.out.println("事务开始");
//执行方法
result=method.invoke(target, args);
System.out.println("事务结束"); </span>
return result;
}
}
cglib动态代理:
cglib:code generated library,代码生成 library。百科上说它是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。Hibernate用它来实现PO(Persistent Object 持久化对象)字节码的动态生成。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。
cglib底层使用小而快的字节码处理框架ASM,来转换字节码并生成新的类。
cglib目前版本为2.2,分两种,一种是包含了ASM的cglib-nodep-2.2.jar,中间的nodep是no dependence的缩写,意思是不需要依赖其它jar包提供ASM。另一种是cglib-2.2.jar,则没有包括ASM,由于cglib的版本与ASM的版本需要匹配,因此建议用nodep版本的。
jdk的动态代理要求真实类与代理类必须实现共同接口,而cglib则没有这个要求。cglib生成的代理类是继承真实类,最终调用父类即真实类的方法来实现代理的。
使用cglib主要涉及类Enhancer和接口MethodInterceptor。
实现接口的MethodInterceptor的intercept方法,在此方法中编写处理其它事务的逻辑代码,最后调用invokeSuper()方法触发执行真实类的方法。
new 一个Enhancer对象,并设置其superclass属性的值为真实类,设置其callBack属性的值为方法Intercept的所在类的对象,最后调用Enhancer对象的create方法,即可获得真是类的一个代理对象。
create方法会生成一个真实类的子类。
/**
* 真实类
*/
public class RealBean {
public void create() {
System.out.println("do create");
}
public void update() {
System.out.println("do update");
}
}
/**
* 实现MethodInterceptor接口的intercept方法,定义生成代理类的方法
*
* @author Fiona Lee
* @version 1.0, 2015-6-1
* @since 1.0, 2015-6-1
*/
public class BeanProxyer implements MethodInterceptor {
private List<String> userOpers = null;
public Object getProxyer(Object obj, List<String> userOpers) {
this.userOpers = userOpers;
Enhancer enhancer = new Enhancer();
// 以真实类为父类
enhancer.setSuperclass(obj.getClass());
// 设置intercept方法所在类
enhancer.setCallback(this);
// 生成代理类-作为真是类的子类
return enhancer.create();
}
public Object intercept(Object realBean, Method method, Object[] methodAguments, MethodProxy methodProxy) throws Throwable {
if (userOpers.contains(method.getName())) {
// 反射调用父类的方法
return methodProxy.invokeSuper(realBean, methodAguments);
} else {
System.out.println("没有执行方法" + method.getName() + "的权限!");
return null;
}
}
}
/**
<span style="white-space:pre"> </span> * 测试
<span style="white-space:pre"> </span> * @param args
<span style="white-space:pre"> </span> */
<span style="white-space:pre"> </span>public static void main(String[] args) {
<span style="white-space:pre"> </span>RealBean bean = new RealBean();
<span style="white-space:pre"> </span>List<String> userOpers = new ArrayList<String>();
<span style="white-space:pre"> </span>userOpers.add("create");
<span style="white-space:pre"> </span>RealBean proxy = (RealBean) new BeanProxyer().getProxyer(bean, userOpers);
<span style="white-space:pre"> </span>proxy.create();
<span style="white-space:pre"> </span>proxy.update();
<span style="white-space:pre"> </span>}
do create
没有执行方法update的权限!
Spring AOP:
Spring AOP的那些概念真的很难理解,看了好多资料,都看不进去,最后搜到一篇IBM developerWorks上的文章,感觉不错,链接地址为http://www.ibm.com/developerworks/cn/java/j-lo-springaopcglib/#icomments,简述如下:
AOP(Aspect Orient Programming),也就是面向方面编程,作为面向对象编程的一种补充,专门用于处理系统中分布于各个模块(不同方法)中的交叉关注点的问题,在 Java EE 应用中,常常通过 AOP 来处理一些具有横切性质的系统级服务,如事务管理、安全检查、缓存、对象池管理等。AOP 实现的关键就在于 AOP 框架自动创建的 AOP 代理,AOP 代理主要分为静态代理和动态代理两大类,静态代理以 AspectJ 为代表;而动态代理则以 Spring AOP 为代表。
AspectJ 是在编译时增强,即不是生成代理类,而是会在编译时直接将其它代码添加到真实类的class文件中。
spring AOP是在运行时增强,生成代理类。
使用AOP时,首先要在配置文件中,作如下配置:
<!-- 启动AOP 支持 -->
<aop:aspectj-atuoproxy/>
如果不是在配置文件中声明aspect类,而是采用注解方式,还要在配置文件中注入:
<!-- 配置处理注解 @AspectJ的类 --> <bean class="org.springframework.aop.aspectj.annotation. AnnotationAwareAspectJAutoProxyCreator"/>注解方式,只需对bean加@Aspect注解,即为定义了一个方面类。