Spring AOP使用的核心技術是動態代理,說到動態代理就不得不和設計模式中的代理模式聯繫起來,通過代理模式我們可以對目標類進行功能增強,在某個方法的執行前後增加一些操作,例如計算方法執行效率、打印日誌等。
看下面的例子,我們有一個目標類Target,我們需要在目標類的test方法中增加日誌打印功能,這時候我們就可以通過代理模式來實現:
- package com.proxy.test;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- class Target {
- public void test(){
- System.out.println("Target test");
- }
- }
- class TargetProxy
- {
- private Target target;
- private Log logger = LogFactory.getLog(TargetProxy.class);
- public TargetProxy(Target target) {
- this.target = target;
- }
- public void test()
- {
- logger.info("*****方法執行前**********");
- target.test();
- logger.info("*****方法執行後**********");
- }
- }
- public class ProxyTest{
- public static void main(String[] args) {
- Target target = new Target();
- TargetProxy proxy = new TargetProxy(target);
- proxy.test();
- }
- }
實現方式有兩種,一種是通過JDK自帶的動態代理,另外一種則是使用Cglib實現。
1.使用JDk實現動態代理
例如在Service層,我們有兩個業務邏輯類LoginServiceImpl和UserServiceImpl:
- interface LoginService{
- public boolean checkUser();
- }
- class LoginServiceImpl implements LoginService{
- public boolean checkUser() {
- System.out.println("LoginServiceImpl checkUser");
- return false;
- }
- }
- interface UserService{
- public String getUserName();
- }
- class UserServiceImpl implements UserService{
- public String getUserName() {
- System.out.println("UserServiceImpl getUserName");
- return null;
- }
- }
- package com.proxy.test.jdk;
- import java.lang.reflect.InvocationHandler;
- import java.lang.reflect.Method;
- import java.lang.reflect.Proxy;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- interface LoginService{
- public boolean checkUser();
- }
- class LoginServiceImpl implements LoginService{
- public boolean checkUser() {
- System.out.println("LoginServiceImpl checkUser");
- return false;
- }
- }
- interface UserService{
- public String getUserName();
- }
- class UserServiceImpl implements UserService{
- public String getUserName() {
- System.out.println("UserServiceImpl getUserName");
- return null;
- }
- }
- class ProxyHandler implements InvocationHandler{
- private Object target;
- private Log logger = LogFactory.getLog(ProxyHandler.class);
- public void setTarget(Object target) {
- this.target = target;
- }
- public Object invoke(Object proxy, Method method, Object[] param)
- throws Throwable {
- logger.info("*********代理方法執行前************");
- Object retObj = method.invoke(target, param);
- logger.info("*********代理方法執行後************");
- return retObj;
- }
- }
- public class ProxyTestJDK {
- public static void main(String[] args) {
- //創建目標對象
- LoginService loninService = new LoginServiceImpl();
- UserService userService = new UserServiceImpl();
- ProxyHandler proxyHandler = new ProxyHandler();
- //創建LoginService代理對象
- proxyHandler.setTarget(loninService);
- LoginService loninService$Proxy = (LoginService) Proxy.newProxyInstance(loninService.getClass().getClassLoader(),
- loninService.getClass().getInterfaces(), proxyHandler);
- loninService$Proxy.checkUser();
- //創建UserService代理對象
- proxyHandler.setTarget(userService);
- UserService userService$Proxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(),
- userService.getClass().getInterfaces(), proxyHandler);
- userService$Proxy.getUserName();
- }
- }
- 十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept
- 信息: *********代理方法執行前************
- LoginServiceImpl checkUser
- 十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept
- 信息: *********代理方法執行後************
- 十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept
- 信息: *********代理方法執行前************
- UserServiceImpl getUserName
- 十月 17, 2015 1:37:21 下午 com.proxy.test.cglib.CglibProxy intercept
- 信息: *********代理方法執行後************
2.使用Cglib動態代理實現
對於上面的需求我們也可以通過Cglib實現,具體代碼如下:
- package com.proxy.test.cglib;
- import java.lang.reflect.Method;
- import net.sf.cglib.proxy.Enhancer;
- import net.sf.cglib.proxy.MethodInterceptor;
- import net.sf.cglib.proxy.MethodProxy;
- import org.apache.commons.logging.Log;
- import org.apache.commons.logging.LogFactory;
- interface LoginService{
- public boolean checkUser();
- }
- class LoginServiceImpl implements LoginService{
- public boolean checkUser() {
- System.out.println("LoginServiceImpl checkUser");
- return false;
- }
- }
- interface UserService{
- public String getUserName();
- }
- class UserServiceImpl implements UserService{
- public String getUserName() {
- System.out.println("UserServiceImpl getUserName");
- return null;
- }
- }
- class CglibProxy implements MethodInterceptor
- {
- private Log logger = LogFactory.getLog(CglibProxy.class);
- public Object intercept(Object proxy, Method method, Object[] params,
- MethodProxy methodProxy) throws Throwable {
- logger.info("*********代理方法執行前************");
- Object retObj = methodProxy.invokeSuper(proxy, params);
- logger.info("*********代理方法執行後************");
- return retObj;
- }
- //返回目標對象的代理對象
- public Object newProxy(Object target)
- {
- Enhancer enhancer = new Enhancer();
- enhancer.setSuperclass(target.getClass());
- enhancer.setCallback(this);
- enhancer.setClassLoader(target.getClass().getClassLoader());
- return enhancer.create();
- }
- }
- public class ProxyTestCglib {
- public static void main(String[] args) {
- //創建目標對象
- LoginService loninService = new LoginServiceImpl();
- UserService userService = new UserServiceImpl();
- CglibProxy proxy = new CglibProxy();
- //創建代理對象
- LoginService loninService$Proxy = (LoginService)proxy.newProxy(loninService);
- UserService userService$Proxy = (UserService)proxy.newProxy(userService);
- loninService$Proxy.checkUser();
- userService$Proxy.getUserName();
- }
- }
3.二者優缺點分析
使用JDK動態代理,目標類必須實現的某個接口,如果某個類沒有實現接口則不能生成代理對象。
Cglib原理是針對目標類生成一個子類,覆蓋其中的所有方法,所以目標類和方法不能聲明爲final類型。
從執行效率上看,Cglib動態代理效率較高。