在应用AOP编程是主要编程对象是切面,而切面模块化横切关注点。仍然需要定义公共功能,但可以明明确的定义这个功能在哪里,以什么方式应用。并且不必修改受影响的类。这样一来横切关注点就被模块化到特殊的对象(切面)里了。
AOP术语
切面(Aspect):横切关注点
通知(Advice):切面必须要完成的工作
目标(Target):被通知的对象
代理(Proxy):向目标对象应用通知之后创建的对象
使用配置
1)加入jar包
2)在配置文件中加入aop命名空间
3)基于注解的方式
在配置文件中加入如下配置
把横切关注点的代码出现到切面的类,切面首先要是一个IOC中的bean,加入@component注解
切面还需要加入@Aspect注解
4)在类中声明各种通知。
1、声明一个方法。
2、在方法前加入一个注解
3、可以在方法汇总加入一JoinPoint,可以获取一些方法的参数和方法名
AspectJ支持5种类型的通知注解
@Before:前置通知, 在方法执行之前执行
@After:后置通知, 在方法执行之后执行
@AfterRunning:返回通知, 在方法返回结果之后执行
@AfterThrowing:异常通知, 在方法抛出异常之后
@Around:环绕通知, 围绕着方法执行
项目应用
应用场景,在项目中采用前后端分离。规定了前端接收的信息,但是前端无法接收具体的错误信息,这在开发过程中就很不方便。无法很快的定位消息。所以使用了spring的AOP对于开发情况会将错误信息返给前端。具体实现详见
Spring-mvc文件中引入对于aop的使用并且让spring管理起来
<aop:aspectj-autoproxyproxy-target-class="true"/>
<beanclass="com.dmsdbj.itoo.tool.aspect.AfterReturningAspect"/>
具体实现类,使用的事后置环绕,在方法之后执行
@Aspect
public class AfterReturningAspect {
private static final Logger logger = LoggerFactory.getLogger(AfterReturningAspect.class);
private final Map clazzMap = new HashMap<String, String>();
public AfterReturningAspect() {
reloadProperties();
//设置定时任务,定时加载属性配置文件
Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
reloadProperties();
}
}, 1000, 60000);
}
/**
* 加载配置文件将其中你的key-value保存到clazzMap中
*/
private void reloadProperties() {
Properties p = new Properties();
try {
InputStream in = new FileInputStream(this.getClass().getClassLoader().getResource("resource.properties").getFile());
p.load(in);
} catch (IOException e) {
logger.error("[AfterReturningAspect.getProperties()]the method of printing log is error", e.getMessage());
}
Enumeration en = p.propertyNames();
while (en.hasMoreElements()) {
String key = (String) en.nextElement();
String property = p.getProperty(key);
clazzMap.put(key, property);
}
}
/**
* 拦截controller将异信息抛给浏览器
* @param rvt 拦截到的Controller给前端返回的ItooResult型实体
*/
@AfterReturning(returning = "rvt",pointcut = "execution(* com.dmsdbj.itoo.*.controller.*.*(..))")
public void log(Object rvt){
ItooResult result = (ItooResult)rvt;
if("true".equals(this.clazzMap.get("aop.printexception.enable")) && result.getException() instanceof Exception){
HttpServletResponse response = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getResponse();
response.reset();
response.setCharacterEncoding("UTF-8");
response.setHeader("Content-Type", "text/plain;charset=UTF-8");
response.setHeader("icop-content-type", "exception");
throw new ItooRuntimeException(result.getException());
}
}
}
不同的环境中aop.printexception.enable的值不相同,通过这个来判定是否会将错误信息抛到前端