代理的實現分動態代理和靜態代理,靜態代理的實現是對已經生成了的JAVA類進行封裝。java
動態代理則是在運行時生成了相關代理累,在JAVA中生成動態代理通常有兩種方式。spring
JDK實現代理生成,是用類 java.lang.reflect.Proxy, 實現方式以下express
EX:測試
public class JDKProxy { public static Object getPoxyObject(final Object c) { return Proxy.newProxyInstance(c.getClass().getClassLoader(), c.getClass().getInterfaces(),// JDK實現動態代理,但JDK實現必須須要接口 new InvocationHandler() { 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; } }); } }
測試代理類方法spa
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實現代理的目標類必須有實現接口.net
2, 生成出來的代理類爲接口實現類,和目標類不能進行轉換,只能轉爲接口實現類進行調用代理
明顯特色:經過此方法生成出來的類名叫作 $Proxy0code
CGLIB是一個開源項目,官方網址是:http://cglib.sourceforge.net/,能夠去上面下載最新JAR包,xml
本項目用的是cglib-3.0.jar對象
本項目還加入了依賴JAR包asm-4.0.jar,asm-util-4.0.jar
實現方式以下
EX:
測試代理類方法
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.");
}
}
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(); } }
1, CGLIB實現方式是對代理的目標類進行繼承
2, 生成出了的代理類能夠沒方法,生成出來的類能夠直接轉換成目標類或目標類實現接口的實現類,因JAVA向上轉換
明顯特色:經過輸出看出,看出生成出的代理類的parent類爲代理的目標類
在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
commons\commons-logging-1.1.1\commons-logging-1.1.1.jar
aopalliance\aopalliance.jar
lib\aspectjweaver.jar
先簡單的實現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開源項目生成的攔截類的子類.