概念
两个特点:
- IOC控制反转
- AOP主要用来处理公共的代码
例如一个案例就是添加用户,重复的代码包含了记录日志、事务提交和事务回滚等,都是重复的,为了简单,交给AOP来做。
- 即将复杂的需求分解出不同方面,将散布在系统中的公共功能集中解决。(例如有关security,persistence,logging等不同方面的代码,)
- 采用代理机制组装起来运行,在不改变原程序的基础上对代码段进行增强处理,增加新的功能。
回到添加用户的案例,把不同面的代码单独抽出去,当程序运行到方法时,例如方法前,可以动态将该面的程序动态的切进去,方法运行完也可以动态的切进去。
通过代理对象调用原来对象的方法。代理对象方法前后都可插入代码,这些代码就是增强处理。动态代理的经典实现。
所谓面向切面编程,即一种通过预编译和运行期动态代理的方式,实现在不修改源代码的情况下给程序动态添加功能的技术。
相关术语
增强处理:
- 前置增强
- 后置增强
- 环绕增强、异常抛出增强、最终增强等类型
切入点Pointcut : 往哪里切
连接点 Join Point:切的地方会产生连接点,根据连接点获得一些参数
切面 Aspect:
目标对象 Target object:切的是谁
AOP代理:指代增强
织入 Weaving:动态切入
案例
例如下面的,插入AOP
public class UserServiceImpl implements UserServie{
private UserDao userDao;
@Override
public void show() {
userDao.show();
}
}
想在show方法之前打印日志,show方法之后也打印日志。不建议System.out.println()
。在打印日志的时候,用到log,输出打印的信息并会带上确定的时间,方便排查错误。
import org.apache.log4j.Logger;
public class Log {
private Logger logger = Logger.getLogger(Log.class);
public static void main(String[] args){
logger.info("打印日志, info");
logger.debug("打印日志, debug");
logger.warn("打印日志, warn");
logger.error("打印日志, error");
}
}
如何在show方法执行结束后运行呢?
添加切点。
<aop:pointcut expression="execution( * com.kgc.service.. * . * (..))" id="point"/>
然后进行增强处理。
又例如权限拦截器中的示例:
使用Spring AOP实现权限拦截器,用于在方法执行前或执行过程中进行权限校验,例如角色检查。
@Around("@annotation(authCheck)")
public Object doInterceptor(ProceedingJoinPoint joinPoint, AuthCheck authCheck) throws Throwable {
// 获取注解中的权限要求
String mustRole = authCheck.mustRole();
// 怎么拿到当前用户的登陆信息呢?
RequestAttributes requestAttributes = RequestContextHolder.currentRequestAttributes();
// 转换为servlet
HttpServletRequest request = ((ServletRequestAttributes) requestAttributes).getRequest();
User loginUser = userService.getLoginUser(request);
// 获取用户的权限类型
UserRoleEnum mustRoleEnum = UserRoleEnum.getEnumByValue(mustRole);
// 如果权限要求为空,则继续执行原来的方法
if (mustRoleEnum == null){
return joinPoint.proceed();
}
// 反之,以下的代码就是必须有权限才会通过
// 也要将获取到当前用户的角色转换成枚举类,方便使用
UserRoleEnum userRoleEnum = UserRoleEnum.getEnumByValue(loginUser.getUserRole());
// 如果为空则异常
if (userRoleEnum == null){
throw new BusinessException(ErrorCode.NOT_AUTH_ERROR);
}
// 要对必须有管理员权限,即mustRoleEnum为ADMIN,但是用户的权限不是管理员权限,则异常
if (UserRoleEnum.ADMIN.equals(mustRoleEnum) && !UserRoleEnum.ADMIN.equals(userRoleEnum)){
throw new BusinessException(ErrorCode.NOT_AUTH_ERROR);
}
// 其他情况就是通过权限校验的
return joinPoint.proceed();
}