JAVA 代理实现
代理的实现分动态代理和静态代理,静态代理的实现是对已经生成了的JAVA类进行封装。
动态代理则是在运行时生成了相关代理累,在JAVA中生成动态代理一般有两种方式。
JDK自带实现方法
JDK实现代理生成,是用类 java.lang.reflect.Proxy, 实现方式如下
EX:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Calendar; public class JDKProxy { public static Object getPoxyObject(final Object c) { return Proxy.newProxyInstance(c.getClass().getClassLoader(), c .getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub Object reObj = null; System.out.print("you say: "); reObj = method.invoke(c, args); System.out.println(" [" + Calendar.getInstance().get(Calendar.HOUR) + ":" + Calendar.getInstance().get(Calendar.MINUTE) + " " + Calendar.getInstance().get(Calendar.SECOND) + "]"); return reObj; } }); } }
public class ServiceTestImpl implements ServiceTest{ @Override public void saySomething(String a) { System.out.println(a); } }
public interface ServiceTest { public void saySomething(String a); }
测试代理类方法
public class TestForPoxy { public static void main(String[] args) { ServiceTest service = new ServiceTestImpl(); System.out.println(service.getClass().getSimpleName()); ServiceTest poxyService = (ServiceTest) JDKProxy.getPoxyObject(service); System.out.println(poxyService.getClass().getSuperclass()); poxyService.saySomething("hello,My QQ code is 107966750."); poxyService.saySomething("what 's your name?"); poxyService.saySomething("only for test,hehe."); } }
1, Proxy实现代理的目标类必须有实现接口
2, 生成出来的代理类为接口实现类,和目标类不能进行转换,只能转为接口实现类进行调用
明显特点:通过此方法生成出来的类名叫做 $Proxy0
用CGLIB包实现
CGLIB是一个开源项目,官方网址是:http://cglib.sourceforge.net/,可以去上面下载最新JAR包,
本项目用的是cglib-3.0.jar
本项目还加入了依赖JAR包asm-4.0.jar,asm-util-4.0.jar
实现方式如下
EX:
public class CGLIBProxy { public static Object getPoxyObject(Object c) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(c.getClass()); enhancer.setCallback(new MethodInterceptor() { public Object intercept(Object arg0, Method arg1, Object[] arg2, MethodProxy proxy) throws Throwable { System.out.print("you say: "); proxy.invokeSuper(arg0, arg2); System.out.println(" [" + Calendar.getInstance().get(Calendar.HOUR) + ":" + Calendar.getInstance().get(Calendar.MINUTE) + " " + Calendar.getInstance().get(Calendar.SECOND) + "]"); return null; } }); return enhancer.create(); } }
测试代理类方法
public class TestForPoxy { public static void main(String[] args) { ServiceTest service = new ServiceTestImpl(); System.out.println(service.getClass().getSimpleName()); // ServiceTest poxyService = (ServiceTest) JDKProxy.getPoxyObject(service); ServiceTest poxyService = (ServiceTest) CGLIBProxy.getPoxyObject(service); System.out.println(poxyService.getClass().getSuperclass()); poxyService.saySomething("hello,My QQ code is 107966750."); poxyService.saySomething("what 's your name?"); poxyService.saySomething("only for test,hehe."); } }
1, CGLIB实现方式是对代理的目标类进行继承
2, 生成出了的代理类可以没方法,生成出来的类可以直接转换成目标类或目标类实现接口的实现类,因JAVA向上转换
明显特点:通过输出看出,看出生成出的代理类的parent类为代理的目标类
Spring AOP的代理类机制分析
在spring中,bean都是由动态代理生成出来的,那么到底是用JDK的Proxy类实现呢,还是用CGLIB方式实现呢。
AOP Spring需要的依赖JAR包有:
spring-asm-3.2.0.M1.jar
spring-beans-3.2.0.M1.jar
spring-context-3.2.0.M1.jar
spring-core-3.2.0.M1.jar
spring-expression-3.2.0.M1.jar
spring-aop-3.2.0.M1.jar
spring-aspects-3.2.0.M1.jar
commonscommons-logging-1.1.1commons-logging-1.1.1.jar
aopallianceaopalliance.jar
libaspectjweaver.jar
实现AOP
先简单的实现AOP
配置如下
<?xml version="1.0" encoding="utf-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation=" http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-3.2.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-3.2.xsd"> <bean id="test" class="org.ben.spring.service.Test" /> <bean id="aspectBean" class="org.ben.spring.TestAspect" /> <!-- 对Test类进行AOP拦截 --> <aop:config> <aop:aspect id="TestAspect" ref="aspectBean"> <!--配置切面--> <aop:pointcut id="businessService" expression="execution(* org.ben.spring.service.Test.say(..))" /> <aop:before pointcut-ref="businessService" method="doBefore" /> <aop:after pointcut-ref="businessService" method="doAfter" /> </aop:aspect> </aop:config> </beans>
然后进行运行结果如下,表示AOP拦截成功
AOP测试类 public class TestBeans { public static void main(String[] args) { ApplicationContext ctx = new ClassPathXmlApplicationContext("test.xml"); Test test=(Test) ctx.getBean("test"); System.out.println(test.getClass().getSimpleName()); test.say(); } }
输出:
do something in befor
welcome for test
do something in after
打印代理类的生成方式
第一种情况, Test不实现任何接口,代码如下 public class Test { public void say() { System.out.println("welcome for test,My QQ is 107966750"); } }
在TestBeans中加入打印当前对象的名称
如下:
ApplicationContext ctx = new ClassPathXmlApplicationContext("test.xml"); Test test=(Test) ctx.getBean("test"); System.out.println(test.getClass().getSimpleName()); test.say(); 输出: Test$$EnhancerByCGLIB$$4791b36c super class is class org.ben.spring.service.Test do something in befor welcome for test do something in after
明显看到用了AOP之后,输出的是代理类对象Test$$EnhancerByCGLIB$$bb9b6a7c.而且它的父类是我们的代理目标类。说明是有CGLIB生成的
第二种情况
XML的配置不变,改变代理目标类Test的实现方法,如下
public class Test implements TestInter{ public void say() { System.out.println("welcome for test,My QQ is 107966750"); } }
和原来不同的是多继承了一个接口,接口中定义了say()方法
在TestBeans中加入打印当前对象的名称
如下:
ApplicationContext ctx = new ClassPathXmlApplicationContext("test.xml"); TestInter test=(TestInter) ctx.getBean("test"); System.out.println(test.getClass().getSimpleName()); System.out.println("super class is "+test.getClass().getSuperclass()); test.say();
输出:
$Proxy0
super class is class java.lang.reflect.Proxy
do something in befor
welcome for test,My QQ is 107966750
do something in after
结论
Spring AOP中,当拦截对象实现了接口时,生成方式是用JDK的Proxy类。当没有实现任何接口时用的是GCLIB开源项目生成的拦截类的子类.
转:http://www.cnblogs.com/springsource/archive/2012/08/30/2664050.html