JAVA 代理實現
代理的實現分動態代理和靜態代理,靜態代理的實現是對已經生成了的JAVA類進行封裝。
動態代理則是在運行時生成了相關代理累,在JAVA中生成動態代理一般有兩種方式。
JDK自帶實現方法
JDK實現代理生成,是用類 java.lang.reflect.Proxy, 實現方式如下
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;
}
});
}
}
測試代理類方法
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
commons\commons-logging-1.1.1\commons-logging-1.1.1.jar
aopalliance\aopalliance.jar
lib\aspectjweaver.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開源項目生成的攔截類的子類.
附上本文測試的源碼內容 源碼下載