jdk 静态代理、动态代理、cglib、spring AOP

代理模式的定义:

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。


模式结构:

         

抽象角色:声明真实对象和代理对象的共同接口。
代理角色:代理对象角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。

优点:

职责清晰:真实角色只需实现实际的业务逻辑,不需关心其非本职的事务,通过后期的代理完成其他事务,附带结果就是编程简洁清晰。

在程序设计中有一个类的单一性原则问题,这个原则很简单,就是每个类的功能尽可能单一。为什么要单一,因为只有功能单一这个类被改动的可能性才会最小,如果你将其它事务放在真实角色类里面,真实角色类就既要负责自己本身业务逻辑、又要负责其它事务,那么就有两个导致该类变化的原因,如果其它事务规则一旦变化,这个类就必需得改,显然这不是一个好的设计。

代理角色就是客户端和真是角色间的中间层,起到了保护真实角色的作用。

高扩展性


静态代理:

/** 
 * 定义一个账户接口 
 *  
 * @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注解,即为定义了一个方面类。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值