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)

切面 = 切入点 + 通知。

对一个切面进行定义时:定义切入点&&定义通知

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