Spring AOP主要有兩種代理方式:
1.JDK動態代理 2.cglib代理
1、如果目標對象實現了接口,默認情況下會采用JDK的動態代理實現AOP
2、如果目標對象實現了接口,可以強制使用CGLIB實現AOP
3、如果目標對象沒有實現了接口,必須采用CGLIB庫,spring會自動在JDK動態代理和CGLIB之間轉換
注:JDK動態代理要比cglib代理執行速度快,但性能不如cglib好。所以在選擇用哪種代理還是要看具體情況,一般單例模式用cglib比較好,具體原因請自行百度。
一、JDK動態代理實現(原理是使用反射機制)
1、定義TestService接口
[java] view plain copy
package io.mykit.proxy.jdk.service;
/**
* JDK動態代理Service
* @author liuyazhuang
*
*/
public interface TestService {
int add();
}
2、定義TestServiceImpl實現類
[java] view plain copy
package io.mykit.proxy.jdk.service.impl;
import io.mykit.proxy.jdk.service.TestService;
public class TestServiceImpl implements TestService {
@Override
public int add() {
System.out.println("開始執行add...");
return 0;
}
}
3、定義動態代理類JDKDynamicProxy
[java] view plain copy
package io.mykit.proxy.jdk.handler;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDK的動態代理實現
* @author liuyazhuang
*
*/
public class JDKDynamicProxy implements InvocationHandler {
//被代理的目標對象
private Object proxyObj;
/**
* Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
* loader :類加載器 一個ClassLoader對象,定義了由哪個ClassLoader對象來對生成的代理對象進行加載
* interfaces:一個Interface對象的數組,表示的是我將要給我需要代理的對象提供一組什么接口,如果我提供了一組接口給它,那么這個代理對象就宣稱實現了該接口(多態),這樣我就能調用這組接口中的方法了
* h :一個InvocationHandler對象,表示的是當我這個動態代理對象在調用方法的時候,會關聯到哪一個InvocationHandler對象上
*/
public Object newProxy(Object proxyObj){
this.proxyObj = proxyObj;
//返回一個代理對象
return Proxy.newProxyInstance(proxyObj.getClass().getClassLoader(), proxyObj.getClass().getInterfaces(), this);
}
/**
* 執行目標對象
* Object proxy:被代理的對象
* Method method:要調用的方法
* Object args[]:方法調用時所需要的參數
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object object = method.invoke(this.proxyObj, args); // 通過反射機制調用目標對象的方法
after();
return object;
}
public void before(){
System.out.println("開始執行目標對象之前...");
}
public void after(){
System.out.println("開始執行目標對象之后...");
}
}
4、實現測試類ProxyTest
[java] view plain copy
package io.mykit.proxy.jdk;
import io.mykit.proxy.jdk.handler.JDKDynamicProxy;
import io.mykit.proxy.jdk.service.TestService;
import io.mykit.proxy.jdk.service.impl.TestServiceImpl;
/**
* 動態代理測試
*
* @author liuyazhuang
*
*/
public class ProxyTest {
public static void main(String[] args) {
// 我們要代理的真實對象
TestService testService = new TestServiceImpl();
testService.add();// 不是用代理
System.out.println("===================================");
JDKDynamicProxy JDKDynamicProxyTarget = new JDKDynamicProxy();
TestService testServiceProxy = (TestService) JDKDynamicProxyTarget.newProxy(testService);
// 執行代理類的方法
testServiceProxy.add();
}
}
5、測試結果如下
[plain] view plain copy
開始執行add...
===================================
開始執行目標對象之前...
開始執行add...
開始執行目標對象之后...
二、CGLIB代理
1、創建TestCGLIBServiceImpl類
[java] view plain copy
package io.mykit.proxy.cglib.service.impl;
/**
* 未實現接口的類
* @author liuyazhuang
*
*/
public class TestCGLIBServiceImpl {
public int add() {
System.out.println("開始執行add...");
return 0;
}
}
2、創建代理類CGLIBProxy
[java] view plain copy
package io.mykit.proxy.cglib.handler;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
/**
* 基於CGLIB實現
* @author liuyazhuang
*
*/
public class CGLIBProxy implements MethodInterceptor {
private Object targetObject;// 被代理的目標對象
/**
* 構造代理對象
* @param targetObject 傳遞的真實對象
* @return 代理對象
*/
public Object createProxyInstance(Object targetObject) {
this.targetObject = targetObject;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetObject.getClass());// 設置代理目標
enhancer.setCallback(this);// 設置回調
return enhancer.create();
}
/**
* 在代理實例上處理方法調用並返回結果
* @param object : 代理類
* @param method :被代理的方法
* @param args :該方法的參數數組
* @param methodProxy : 方法代理
*/
@Override
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodproxy) throws Throwable {
Object result = null;
try {
System.out.println("前置處理開始 ...");
result = methodproxy.invoke(targetObject, args);// 執行目標對象的方法
System.out.println("后置處理開始 ...");
} catch (Exception e) {
System.out.println(" 異常處理 ...");
} finally {
System.out.println(" 調用結束 ...");
}
return result;
}
}
3、創建測試類ProxyTest
[java] view plain copy
package io.mykit.proxy.cglib;
import io.mykit.proxy.cglib.handler.CGLIBProxy;
import io.mykit.proxy.cglib.service.impl.TestCGLIBServiceImpl;
/**
* 測試CGLIB代理
* @author liuyazhuang
*
*/
public class ProxyTest {
public static void main(String[] args) {
//我們要代理的真實對象
TestCGLIBServiceImpl testCGLIB = new TestCGLIBServiceImpl();
testCGLIB.add();
System.out.println("======================================");
CGLIBProxy CGLIBproxy = new CGLIBProxy();
TestCGLIBServiceImpl testCGLIBProxy = (TestCGLIBServiceImpl) CGLIBproxy.createProxyInstance(testCGLIB);
testCGLIBProxy.add();
}
}
4、測試結果
[plain] view plain copy
開始執行add...
======================================
前置處理開始 ...
開始執行add...
后置處理開始 ...
調用結束 ...
5、pom.xml中添加的Jar包
[html] view plain copy
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<skip_maven_deploy>false</skip_maven_deploy>
<jdk.version>1.8</jdk.version>
<spring.version>4.1.0.RELEASE</spring.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-messaging</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jms</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context-support</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-web</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-webmvc</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjtools</artifactId>
<version>1.9.1</version>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
<version>3.0.1</version>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-log4j12</artifactId>
<version>1.7.2</version>
</dependency>
<dependency>
<groupId>commons-logging</groupId>
<artifactId>commons-logging</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib-nodep</artifactId>
<version>2.1_3</version>
</dependency>
</dependencies>