aop:java的动态代理,对于oop这种设计理念,aop能够更好地减少代码的冗余,并且相比于纵向的功能增加,aop能够提供横向功能的扩展。纵向的功能的增加其实很好理解,就是几个对象所用代码有类似,但是又不是完全一样,这时我们可以通过一个父类,把类似代码归为一个方法,这样当不同对象继承父类时,调用相同逻辑的方法并加上自身的不同的业务代码即可。
因为随着软件开发的系统越来越复杂,工程师认识到,传统的OOP程序经常表现出一些不自然的现象,核心业务中总掺杂着一些不相关联的特殊业务,如日志记录,权限验证,事务控制,性能检测,错误信息检测等等,这些特殊业务可以说和核心业务没有根本上的关联而且核心业务也不关心它们,比如在用户管理模块中,该模块本身只关心与用户相关的业务信息处理,至于其他的业务完全可以不理会,我们看一个简单例子协助理解这个问题。
/**
* Created by zejian on 2017/2/15.
* Blog : http://blog.csdn.net/javazejian [原文地址,请尊重原创]
*/
public interface IUserService {
void saveUser();
void deleteUser();
void findAllUser();
}
//实现类
public class UserServiceImpl implements IUserService {
//核心数据成员
//日志操作对象
//权限管理对象
//事务控制对象
@Override
public void saveUser() {
//权限验证(假设权限验证丢在这里)
//事务控制
//日志操作
//进行Dao层操作
userDao.saveUser();
}
@Override
public void deleteUser() {
}
@Override
public void findAllUser() {
}
}
上述代码中我们注意到一些问题,权限,日志,事务都不是用户管理的核心业务,也就是说用户管理模块除了要处理自身的核心业务外,还需要处理权限,日志,事务等待这些杂七杂八的不相干业务的外围操作,而且这些外围操作同样会在其他业务模块中出现,这样就会造成如下问题
代码混乱:核心业务模块可能需要兼顾处理其他不相干的业务外围操作,这些外围操作可能会混乱核心操作的代码,而且当外围模块有重大修改时也会影响到核心模块,这显然是不合理的。
代码分散和冗余:同样的功能代码,在其他的模块几乎随处可见,导致代码分散并且冗余度高。
代码质量低扩展难:由于不太相关的业务代码混杂在一起,无法专注核心业务代码,当进行类似无关业务扩展时又会直接涉及到核心业务的代码,导致拓展性低。
事实上我们知道诸如日志,权限,事务,性能监测等业务几乎涉及到了所有的核心模块,如果把这些特殊的业务代码直接到核心业务模块的代码中就会造成上述的问题,而工程师更希望的是这些模块可以实现热插拔特性而且无需把外围的代码入侵到核心模块中,这样在日后的维护和扩展也将会有更佳的表现,假设现在我们把日志、权限、事务、性能监测等外围业务看作单独的关注点(也可以理解为单独的模块),每个关注点都可以在需要它们的时刻及时被运用而且无需提前整合到核心模块中,这种形式相当下图:
/**
* Created by zejian on 2017/2/15.
* Blog : http://blog.csdn.net/javazejian [原文地址,请尊重原创]
* 切面类
*/
public aspect MyAspectJDemo {
/**
* 定义切点,日志记录切点
*/
pointcut recordLog():call(* HelloWord.sayHello(..));
/**
* 定义切点,权限验证(实际开发中日志和权限一般会放在不同的切面中,这里仅为方便演示)
*/
pointcut authCheck():call(* HelloWord.sayHello(..));
/**
* 定义前置通知!
*/
before():authCheck(){
System.out.println("sayHello方法执行前验证权限");
}
/**
* 定义后置通知
*/
after():recordLog(){
System.out.println("sayHello方法执行后记录日志");
}
}
定义一个切面类,这样能够在执行业务代码之前和之后进行相应的方法的调用,就比如before和after,非常方便,这就是横向切片。这样的好处就是日志的方法,鉴权的方法不用写多次,可以理解为继承这个aspect之后,会触发相应的方法,那么这个方法就是pointcut,根据这个pointcut进行前后的逻辑处理。