AOP的引入及AOP相關術語

AOP引入:動態代理處理公共代碼

重複代碼問題

拿我上一個博客那個例子來說,需要事務處理的不僅僅只有一個方法,如果每個方法都使用同樣的流程進行事務處理,大量的重複代碼就會出現。

就像下面這樣:


   public boolean transfer(String fromUsername, String toUsername, double money){

        transactionManager.openTranscation();
        try {
            User from = userDao.getUserByUsername(fromUsername);
            User to = userDao.getUserByUsername(toUsername);

            from.setAccount(from.getAccount() - money);
            to.setAccount(to.getAccount() + money);

            userDao.updateUser(from);
            userDao.updateUser(to);
            transactionManager.commit();
        }catch (Exception e){
            transactionManager.rollback();
            throw new RuntimeException(e);
        }finally {
            transactionManager.closeTransaction();
        }
        return true;
    }

如果需要事務處理,就會出現和上面代碼流程及其類似的代碼,不同的地方只有業務部分的代碼。

所以,可以提取出如下的公共代碼

	   public Object function(...){

        transactionManager.openTranscation();
        try {
  			
			/******業務代碼******/

            transactionManager.commit();
        }catch (Exception e){
            transactionManager.rollback();
            throw new RuntimeException(e);
        }finally {
            transactionManager.closeTransaction();
        }
    }

到這裏,可以想到Java的動態代理。使用動態代理對象調用方法時,每個方法都會調用InvocationHandler.invoke()方法,因此,公共代碼可以放到invoke()方法中

在這裏,使用代理模式,對於需要進行事務處理的方法時,通過代理對象進行調用。對於不需要事務處理的方法,就可以使用被代理對象直接調用。先看一下類圖:

在這裏插入圖片描述

思路是這樣的,Servcice通過一個工廠方法創建一個動態代理對象,如果使用該代理方法調用,則會加入事務處理,如果使用被代理對象本身的方法,則不會加入事務處理。

實現代碼如下:

@Service("userService")
public class UserServiceImpl implements IUserService {
    @Autowired
    private UserDaoImpl userDao;
    @Autowired
    private TransactionManager transactionManager;

    /**
     * 沒有實現事務處理,使用代理模式對該方法進行增強
     */
    @Override
    public boolean transfer(String fromUsername, String toUsername, double money) {
            User from = userDao.getUserByUsername(fromUsername);
            User to = userDao.getUserByUsername(toUsername);

            if(from.getAccount() < money)
                return false;
            from.setAccount(from.getAccount() - money);
            to.setAccount(to.getAccount() + money);

            userDao.updateUser(from);
            userDao.updateUser(to);
            return true;
    }

	//創建一個有事務處理的動態代理對象
    @Override
    public IUserService getTransactionProxy() {
        class InvocationHandlerImpl implements InvocationHandler {
            IUserService userService;

            public InvocationHandlerImpl(IUserService userService) {
                this.userService = userService;
            }

            @Override
            public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
                transactionManager.openTranscation();
                try{
                    Object retvalue =  method.invoke(userService, objects);
                    transactionManager.commit();
                    return retvalue;
                }catch (Exception e){
                    transactionManager.rollback();
                    throw new RuntimeException(e);
                }finally {
                    transactionManager.closeTransaction();
                }
            }
        }
        return (IUserService) Proxy.newProxyInstance(this.getClass().getClassLoader(),
                this.getClass().getInterfaces(),
                new InvocationHandlerImpl(this));
    }
}

AOP相關概念

AOP(Aspect Orientend Programming)

AOP,面向切面編程。通過預編譯運行期間動態代理實現程序功能的統一維護的一種技術。AOP是OOP的延續。

定義中提到的統一維護,指的就是對公共代碼進行維護。

連接點(JoinPoint)

連接點是指被代理對象的方法。這些方法可以通過AOP進行功能性的增強。

切入點(PointCut)

被AOP進行功能性增強的連接點,被稱作切入點。

目標對象(Target)

被代理的對象,上面例子中的Servcie對象,他需要被代理,實現功能性的增強。

通知(Advice)

對切入點進行功能性增強的部分。

通知的分類:

  • 前置通知
  • 後置通知
  • 異常通知
  • 最終通知
  • 環繞通知

舉例:

	   public Object function(...){

        transactionManager.openTranscation();
        try {
  			
			/******切入點方法調用******/

            transactionManager.commit();
        }catch (Exception e){
            transactionManager.rollback();
            throw new RuntimeException(e);
        }finally {
            transactionManager.closeTransaction();
        }
    }

在切入點方法調用之前的通知transactionManager.openTransaction(),就稱爲前置通知。

在切入點方法調用之後的通知trasactionManager.commit(),稱爲後置通知。

在異常處理中執行的通知trasactionManager.rollback(),稱爲異常通知。

進行資源回收等操作的通知transactionManager.closeTransaction(),稱爲最終通知(在finally代碼塊中)。

對於整個function()方法,被稱作環繞通知。對於環繞通知的處理,可以像上面一樣,當攔截切入點方法後,對切入點方法進行功能性增強;也可以不調用切入點方法,這樣就相當於使用環繞通知修改切入點功能

可以看到,在實現時,需要一個“通知對象”(trasactionManager),對被代理對象的方法進行功能性增強

織入(Weaving)

把功能上的增強應用到被代理對象的過程。就像上面的例子,使用各種通知對切入點進行功能增強的過程。

代理(Proxy)

一個類被AOP植入後,產生一個代理類。通過代理對象調用切入點方法,會執行通知對象的通知及被代理對象的切入點方法(如果使用環繞通知,可能不會執行切入點方法)。(在上面的例子中,採用動態代理的方式,代理的類型和被代理對象的類型是相同的)

切面(Aspect)

切面 = 切入點 + 通知。

對一個切面進行定義時:定義切入點&&定義通知

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