Spring AOP 原理 理解

                                                      Spring AOP 原理 理解

 

 

  

代理模式: 就好比明星和經紀人,經紀人負責接活,負責明星唱歌前會場準備,明星唱歌后收錢。 代理類其實就是在代理對象,前後做了一些其他的處理, 這已經具備 AOP的輪廓了

// 接口
public interface IUserDao {
    void save();

    void find();
}

// 目標對象
public class UserDao implements IUserDao {
    @Override
    public void save() {
        System.out.println("模擬:保存用戶!");
    }

    @Override
    public void find() {
        System.out.println("模擬:查詢用戶");
    }
}

/**
 * 靜態代理 特點:
 *  1. 目標對象必須要實現接口 
 * 2. 代理對象,要實現與目標對象一樣的接口
 */
public class UserDaoProxy implements IUserDao {

    // 代理對象,需要維護一個目標對象
    private IUserDao target = new UserDao();

    @Override
    public void save() {
        System.out.println("代理操作: 開啓事務...");
        target.save(); // 執行目標對象的方法
        System.out.println("代理操作:提交事務...");
    }

    @Override
    public void find() {
        target.find();
    }
}

public class StaticProxyTest {

    /**
     * @param args
     */
    public static void main(String[] args) {

        IUserDao proxy = new UserDaoProxy();
        proxy.save();
    }

}

 

可以看到,靜態代理是必須要有接口的,代理類和目標類都得事先接口,這樣就顯得很麻煩了,每次代理一個目標對象,就得做一個代理類,有沒有一種方式,可以使用一個代理 ,代理多個目標對象呢?

於是就有了動態代理:

動態代理不需要提前建立代理,而是在運行時,爲目標對象動態生成代理類

// 接口
public interface IUserDao {
    void save();

    void find();
}

// 目標對象
public class UserDao implements IUserDao {

    @Override
    public void save() {
        System.out.println("模擬: 保存用戶!");
    }

    @Override
    public void find() {
        System.out.println("查詢");
    }
}




/**
 * 動態代理:JDK 動態代理採用的是反射機制實現
 * 代理工廠,給多個目標對象生成代理對象!
 *
 */
public class ProxyFactory {
 
    // 接收一個目標對象
    private Object target;
 
    public ProxyFactory(Object target) {
        this.target = target;
    }
 
    // 返回對目標對象(target)代理後的對象(proxy)
    public Object getProxyInstance() {
        Object proxy = Proxy.newProxyInstance(
            target.getClass().getClassLoader(),  // 目標對象使用的類加載器
            target.getClass().getInterfaces(),   // 目標對象實現的所有接口
            new InvocationHandler() {            // 執行代理對象方法時候觸發
 
                @Override
                public Object invoke(Object proxy, Method method, Object[] args)
                        throws Throwable {
 
                    // 獲取當前執行的方法的方法名
                    String methodName = method.getName();
                    // 方法返回值
                    Object result = null;
                    if ("find".equals(methodName)) {
                        // 直接調用目標對象方法
                        result = method.invoke(target, args);
                    } else {
                        System.out.println("開啓事務...");
                        // 執行目標對象方法
                        result = method.invoke(target, args);
                        System.out.println("提交事務...");
                    }
                    return result;
                }
            }
        );
        return proxy;
    }
}



public class JDKDynamicProxyTest {

    /**
     * @param args
     */
    public static void main(String[] args) {
        // 目標對象
        IUserDao target = new UserDao();
        // 創建代理類
        IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
        System.out.println("代理對象: "+proxy.getClass());
        proxy.save();

    }

}

 

可以總結一下,JDK 動態代理 

        // 創建代理類
        IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();

實際上 隱藏了動態的去實現 目標對象的一個接口

class $jdkProxy implements IUserDao{}

也就是說 使用JDK 反射方式實現動態代理,目標對象必須實現一個接口,這就可能出現問題了,假設一個類,就是沒有實現接口怎麼辦?

因此就有了使用CGLIB實現動態代理

CGLIB是使用繼承的方式動態生成代理類,這個代理類是繼承目標類的,這個就有個問題,需要目標類不被final修飾。

有點類似

public class UserDao{}
 
// CGLIB 是以動態生成的子類繼承目標的方式實現,程序執行時,隱藏了下面的過程
public class $Cglib_Proxy_class  extends UserDao{}

CGLIB實現

// 目標對象
public class UserDao {

    public void save() {
        System.out.println("模擬: 保存用戶!");
    }

    public void find() {
        System.out.println("查詢");
    }
}

public class CGLIBProxyFactory {

    static class SimpleInterceptor implements MethodInterceptor {
        /**
         * @see org.springframework.cglib.proxy.MethodInterceptor#intercept(java.lang.Object,
         *      java.lang.reflect.Method, java.lang.Object[],
         *      org.springframework.cglib.proxy.MethodProxy)
         */
        @Override
        public Object intercept(Object target, Method methmod, Object[] args, MethodProxy proxy) throws Throwable {
            System.out.println("entering " + methmod.getName());
            Object result = proxy.invokeSuper(target, args);
            System.out.println("leveaing " + methmod.getName());
            return result;
        }

    }

    public static <T> T getProxy(Class<T> cls) {
        Enhancer enhancer = new Enhancer();
        // 繼承目標類
        enhancer.setSuperclass(cls);
        enhancer.setCallback(new SimpleInterceptor());
        return (T) enhancer.create();
    }
}

public class CGLIBProxyTest {
    public static void main(String[] args) {
        //生成代理  沒有接口
        UserDao proxy = (UserDao) CGLIBProxyFactory.getProxy(UserDao.class);
        System.out.println("代理類:"+ proxy.getClass());
        proxy.save();

    }
}

JDK和CGLIB的區別

1.上面可以可以看到 CGLIB是不需要 目標對象實現接口的, CGLIB是通過繼承來實現的

2. JDK動態代理是需要一個具體的目標對象的,但是CGLIB是不需要這麼一個具體對象的

 

Spring AOP 是怎樣實現的呢?

1.AOP 是基於動態代理模式

2.AOP是方法級別的

3.AOP可以分類業務代碼和關注點代碼(日誌,事務等)

 

AOP 是什麼時候生成代理的?

AOP 代理主要分爲靜態代理和動態代理兩大類,靜態代理以 AspectJ 爲代表;而動態代理則以 Spring AOP 爲代表

IOC容器BeanDefinitionMap裏面結構看內容是啥

bean: class [org.springframework.aop.aspectj.AspectJPointcutAdvisor];
 scope=; 
 abstract=false;
 lazyInit=false; 
 autowireMode=0; 
 dependencyCheck=0; 
 autowireCandidate=true; 
 primary=false; 
 factoryBeanName=null; 
 factoryMethodName=null;
 initMethodName=null;
 destroyMethodName=null, 
 org.springframework.aop.aspectj.AspectJPointcutAdvisor#2=Root 
 bean: class [org.springframework.aop.aspectj.AspectJPointcutAdvisor]; 
 scope=; 
 abstract=false;
 lazyInit=false; 
 autowireMode=0; 
 dependencyCheck=0; 
 autowireCandidate=true;
 primary=false;
 factoryBeanName=null; 
 factoryMethodName=null;
 initMethodName=null;
 destroyMethodName=null,
 org.springframework.aop.aspectj.AspectJPointcutAdvisor#3=Root
 bean:class [org.springframework.aop.aspectj.AspectJPointcutAdvisor]; 
 scope=; 
 abstract=false;
 lazyInit=false;
 autowireMode=0; 
 dependencyCheck=0;
 autowireCandidate=true; 
 primary=false; 
 factoryBeanName=null;
 factoryMethodName=null; 
 initMethodName=null;
 destroyMethodName=null, 
 org.springframework.aop.aspectj.AspectJPointcutAdvisor#0=Root 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

參考:

http://www.importnew.com/27469.html

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章