动态代理是JAVA的一大特性。
我们都知道spring有两种主要的思想 Ioc依赖注入 和 Aop Aop的核心就是动态代理.还有struts的拦截器都用了动态代理模式.
动态代理的优势就是实现无侵入式的代码扩展.目前动态代理主要分为JAVA自己提供的动态代理和CGLIB类似框架。JAVA自带的动态代理是需要接口的。CGLIB这种则是直接修改字节码。
首先我们先讲java自带的动态代理.
在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用.nvocationHandler这个接口的唯一一个方法 invoke 方必须用到的.下面我们就来具体的实现
我们先写一个接口
package com.yc.biz;
public interface ProductBiz {
public void addProduct();
public void delProduct();
<pre name="code" class="java">package com.yc.biz;
在动态代理里面必须有个真实的主题
package com.yc.biz;
//真实主题
public class ProductBizImpl implements ProductBiz {
@Override
public void addProduct() {
System.out.println("*******************************");
System.out.println("添加产品");
System.out.println("*******************************");
}
@Override
public void delProduct() {
System.out.println("*******************************");
System.out.println("删除产品");
System.out.println("*******************************");
}
@Override
public void updateProduct() {
System.out.println("*******************************");
System.out.println("修改产品");
System.out.println("*******************************");
}
@Override
public void findall() {
System.out.println("*******************************");
System.out.println(" 查询所有的产品");
System.out.println("*******************************");
}
}
下一步我们要实现InvocationHandler这个接口
package com.yc.advice;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Date;
public class LogAdvice implements InvocationHandler {
//代理模式中一定要有目标类的引用
private Object targetObject; //注意,这个就是目标类的引用
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用目标的对应的方法
Object returnValue=method.invoke(targetObject, args);
String methodName=method.getName();
if( methodName.startsWith("add") || methodName.startsWith("del")|| methodName.startsWith("update") || methodName.startsWith("modify") ){
//在invoke中加入您要增强的代码
log( method, args, targetObject ); //后置增强
}
return returnValue;
}
//创建一个方法来完成创建代理对象
public Object createInstance( Object targetObject ){
this.targetObject=targetObject;
//生成一个代理对象..
// 生成一个代理对象,这个代理对象是根据 目标对象的接口生成的。
Object obj= Proxy.newProxyInstance( targetObject.getClass().getClassLoader() , targetObject.getClass().getInterfaces() , this );
return obj;
//在客户端,我们调用 createInstance()得到一个代理对象,再调用这个代理对象的 方法. -> 它就会自动加调( 因为this ) -> invoke
}
//增强
private void log(Method method, Object[] args, Object targetObject2){
System.out.println("***********************************");
System.out.println("操作的时间:"+ new Date());
System.out.println("调用的目标类是:"+ targetObject2.getClass().getName());
System.out.println("调用的方法是:"+ method.getName() );
System.out.println("参数值:");
if( args!=null){
for( Object arg: args){
System.out.println("\t"+ arg);
}
}
System.out.println("***********************************");
}
}
最后就是 测试类
package com.yc.biz;
import com.yc.advice.LogAdvice;
import com.yc.advice.RightAdvice;
public class Test1 {
public static void main(String[] args) {
RightAdvice ra=new RightAdvice();
ProductBiz pb=new ProductBizImpl();
ProductBiz productBizProxy=(ProductBiz) ra.createInstance(pb);
productBizProxy.addProduct();
productBizProxy.delProduct();
productBizProxy.updateProduct();
productBizProxy.findall();
System.out.println( productBizProxy ); //com.yc.biz.ProductBizImpl@1c7c054
StudentBiz sb=new StudentBizImpl(); //目 ra.createInstance(pb)标类的对象
StudentBiz studentBizProxy= (StudentBiz) ra.createInstance(sb); //根据目标类的对象生成代理对象
studentBizProxy.findAll(); //调用代理对象的被代理的方法
System.out.println( studentBizProxy ); //com.yc.biz.StudentBizImpl@14991ad
System.out.println( productBizProxy ); //com.yc.biz.StudentBizImpl@14991ad
System.out.println("--------------------------------------------------");
LogAdvice la=new LogAdvice();
ProductBiz pbProxy= (ProductBiz) la.createInstance( ra.createInstance(pb) );
pbProxy.addProduct(); // com.yc.biz.StudentBizImpl@1a1cd57
pbProxy.delProduct();
pbProxy.updateProduct();
pbProxy.findall();
}
}
java的jdk动态代理就这样实现完了,下面我们再实现 CGLIB的动态代理 .
什么是cglib呢?
CGLIB其实就是封装了ASM( java字节码操控框架 )了的功能强大, 高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。
CGLIB的动态代理 不是java自带的代理.所以我们要引入cglib-nodep-2.1_3.jar包
第一步我们和jdk代理一样写一个接口
public interface ProductBiz {
public void addProduct();
public void delProduct();
public void updateProduct();
public void findall();
}
public void updateProduct();
public void findall();
}
第二步,必须有个真实的主题
package com.yc.biz;
//真实主题
public class ProductBizImpl implements ProductBiz {
@Override
public void addProduct() {
System.out.println("*******************************");
System.out.println("添加产品");
System.out.println("*******************************");
}
@Override
public void delProduct() {
System.out.println("*******************************");
System.out.println("删除产品");
System.out.println("*******************************");
}
@Override
public void updateProduct() {
System.out.println("*******************************");
System.out.println("修改产品");
System.out.println("*******************************");
}
@Override
public void findall() {
System.out.println("*******************************");
System.out.println(" 查询所有的产品");
System.out.println("*******************************");
}
}
第三步就是实现 MethodInterceptor接口
package com.yc.advice;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Date;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class LogAdvice implements MethodInterceptor {
//代理模式中一定要有目标类的引用
private Object targetObject; //注意,这个就是目标类的引用
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy arg3) throws Throwable {
//调用目标的对应的方法
Object returnValue=method.invoke(targetObject, args);
String methodName=method.getName();
if( methodName.startsWith("add") || methodName.startsWith("del")|| methodName.startsWith("update") || methodName.startsWith("modify") ){
//在invoke中加入您要增强的代码
log( method, args, targetObject ); //后置增强
}
return returnValue;
}
//创建一个方法来完成创建代理对象
public Object createInstance( Object targetObject ){
this.targetObject=targetObject;
Enhancer enhancer=new Enhancer();
// targetObject <- productBizProxy( RightAdvice ) 子类
enhancer.setSuperclass( targetObject.getClass().getSuperclass() );
//enhancer.setClassLoader( targetObject.getClass().getClassLoader() );
enhancer.setCallback( this );
return enhancer.create(); //创建代理类对象.
//在客户端,我们调用 createInstance()得到一个代理对象,再调用这个代理对象的 方法. -> 它就会自动加调( 因为this ) -> invoke
}
//增强
private void log(Method method, Object[] args, Object targetObject2){
System.out.println("***********************************");
System.out.println("操作的时间:"+ new Date());
System.out.println("调用的目标类是:"+ targetObject2.getClass().getName());
System.out.println("调用的方法是:"+ method.getName() );
System.out.println("参数值:");
if( args!=null){
for( Object arg: args){
System.out.println("\t"+ arg);
}
}
System.out.println("***********************************");
}
}
最后就是 测试类
package com.yc.biz;
import com.yc.advice.LogAdvice;
import com.yc.advice.RightAdvice;
public class Test1 {
public static void main(String[] args) {
RightAdvice ra=new RightAdvice();
ProductBizImpl pb=new ProductBizImpl();
final ProductBizImpl productBizProxy=(ProductBizImpl) ra.createInstance(pb);
productBizProxy.addProduct();
productBizProxy.delProduct();
productBizProxy.updateProduct();
productBizProxy.findall();
System.out.println( productBizProxy ); //com.yc.biz.ProductBizImpl@1c7c054
System.out.println("--------------------------------------------------");
LogAdvice la=new LogAdvice();
final ProductBizImpl pbProxy= (ProductBizImpl) la.createInstance( productBizProxy );
pbProxy.addProduct(); // com.yc.biz.StudentBizImpl@1a1cd57
pbProxy.delProduct();
pbProxy.updateProduct();
pbProxy.findall();
}
}
对于这两种动态代理我只有一些浅入的认识,希望大家多提意见!