天天看點

Spring(八)jdk動态代理(AOP簡單實作)

說明

jdk動态代理就是對“裝飾者”設計模式的簡化。使用前提:必須要有接口

編寫過程:

1.目标類:接口+實作類

2.切面類:用于存放通知。

3.工廠類:編寫工廠生成代理

4.測試

UserService 接口 三個方法

public interface UserService {
    public void addUser();
    public void updateUser();
    public void deleteUser();
}      

UserService 實作類,實作了三個方法

public class UserServiceImpl implements UserService

    @Override
    public void addUser() {
        System.out.println("UserServiceDaoImpl addUser");
    }

    @Override
    public void updateUser() {
        System.out.println("UserServiceDaoImpl updateUser");
    }

    @Override
    public void deleteUser() {
        System.out.println("UserServiceDaoImpl deleteUser");
    }

}      

切面類,共兩個方法,before和end。希望在目标類的方法運作前後各調用一次。

public class MyAspect {
    public void before(){
        System.out.println("before");

    }
    public void after(){
        System.out.println("after");
    }
}         

工廠類,用于生成代理。

其中代理類的作用就是将目标類(切入點)和切面類(通知)結合。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class MyProxyFactory
    public static Object createUserService() {
        //目标類
        final UserService userServiceDao = new UserServiceImpl();
        //切面類
        final MyAspect myAspect = new MyAspect();
        //代理類
        Object proxy = Proxy.newProxyInstance(MyProxyFactory.class
                .getClassLoader(), userServiceDao.getClass().getInterfaces(),
                new InvocationHandler() {
                    @Override
                    public Object invoke(Object proxy, Method method,
                            Object[] args) throws Throwable {
                        Object obj = null;
                        //前方法
                        myAspect.before();
                        //執行目标類的方法
                        obj = method.invoke(userServiceDao, args);
                        //後方法
                        myAspect.after();
                        return obj;
                    }
                });
        return      

其中Proxy.newProxyInstance有三個參數。

  • arg1:loader,類加載器,動态代理類,運作時建立,任何類都需要類加載器加載到記憶體。一般使用目前類.class.getClassLoader();也可以使用目标執行個體.getClass().getClassLoader()
  • arg2:代理類要實作的所有接口。目标類例.getClass().getInterfaces();
  • arg3:InvocationHandler處理類,接口必須進行實作。一般采用匿名内部實作。提供的invoke方法。代理類的每一個方法執行都會調用一次invoke。invoke也有三個參數(Object proxy:代理對象, Method method:代理對象目前執行的方法,Object[] args:目前執行方法的參數)。我們可以通過method.getName來為不同的方法實作不同的功能。

測試類

public class Test {
    @org.junit.Test
    public void testProxy(){
        UserService userService=(UserService) MyProxyFactory.createUserService();
        userService.addUser();
        userService.updateUser();
        userService.deleteUser();
    }
}      

運作結果

Spring(八)jdk動态代理(AOP簡單實作)

我們可以看到雖然我們調用的UserService對象,但是在每個方法執行的前後都有輸出before和after。是以我們使用工廠類實作了jdk動态代理。

我們其實可以這樣了解jdk動态代理。

在底層我們在調用代理類的方法時,它會執行invoke方法。

代理類本身沒有什麼功能,它隻是把所有的功能組合在一起。

代理類
addUser(){
    invoke(this,addUser,[]);
}
updateUser(){
    invoke(this,updateUser,[]);
}
deleteUser(){
    invoke(this,deleteUser,[]);
}      

你看懂了嗎?

上面說了 我們可以通過method.getName來為特定的方法實作特定的功能。那麼我們隻為addUser方法執行before和after方法。

我們修改代理類的invoke方法

@Override
                    public Object invoke(Object proxy, Method method,
                            Object[] args) throws Throwable {
                        Object obj = null;
                        if("addUser".equals(method.getName())){
                            //前方法
                            myAspect.before();
                            //執行目标類的方法
                            obj = method.invoke(userServiceDao, args);
                            //後方法
                            myAspect.after();
                        }else{
                            obj = method.invoke(userServiceDao, args);
                        }
                        return