一、AOP:
是对OOP编程方式的一种补充。翻译过来为“面向切面编程”。
可以理解为一个拦截器框架,但是这个拦截器会非常武断,如果它拦截一个类,那么它就会拦截这个类中的所有方法。如对一个目标列的代理,增强了目标类的所有方法。
两个解决办法:
1.不优雅的做法:
在添加增强时,根据方法名去判断,是否添加增强,但是这样就得一直去维护这个增强类。
2.面向切面:
将增强类和拦截条件组合在一起,然后将这个切面配置到 ProxyFactory 中,从而生成代理。
二、AOP 和 切面的关系
1.类比于 OOP 和 对象,AOP 和 切面就是这样的一种关系。
2.也可以将 切面 看成是 AOP 的一个工具。
扫描二维码关注公众号,回复:
98774 查看本文章
三、几个概念
切面(Advisor):是AOP中的一个术语,表示从业务逻辑中分离出来的横切逻辑,比如性能监控,日志记录,权限控制等。
这些功能都可以从核心的业务逻辑中抽离出去。可以解决代码耦合问题,职责更加单一。封装了增强和切点。
增强(Advice):增强代码的功能的类,横切到代码中。
目标:目标方法(JDK代理)或目标类(CGLIB代理)
代理:JDK代理,CGLIB代理。或是通过 ProxyFactory 类生产。
切点:通过一个条件来匹配要拦截的类,这个条件称为切点。如拦截所有带 Controller 注解的类。增强的条件。
连接点:作为增强方法的入参,可以获取到目标方法的信息。
四、实践:自定义一个注解,用Spring-AOP实现给添加这个注解的方法做业务处理
1.POM文件中引入Spring的jar包,其他jar不需要引用。
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aop --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aop</artifactId> <version>${spring.version}</version> </dependency> <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects --> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-aspects</artifactId> <version>${spring.version}</version> </dependency>
2.自定义一个注解
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 监控请求的进度 * @author wangfeixiong */ @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) public @interface ReviewProgressAnnotation { String value(); }
3.配置Spring 开启AOP注解
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:context="http://www.springframework.org/schema/context" xmlns:task="http://www.springframework.org/schema/task" xmlns:mvc="http://www.springframework.org/schema/mvc" xmlns:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/mvc http://www.springframework.org/schema/mvc/spring-mvc.xsd http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd "> <description>Spring MVC Configuration</description> <!-- 加载配置属性文件 --> <context:property-placeholder ignore-unresolvable="true" location="classpath:*.properties"/> <!-- 使用Annotation自动注册Bean --> <context:component-scan base-package="com.future.dcwj"/> <!-- 默认的注解映射的支持,org.springframework.web.servlet.mvc.method.annotation.RequestMappingHandlerMapping --> <mvc:annotation-driven content-negotiation-manager="contentNegotiationManager"> <mvc:message-converters register-defaults="true"> <!-- 将StringHttpMessageConverter的默认编码设为UTF-8 --> <bean class="org.springframework.http.converter.StringHttpMessageConverter"> <constructor-arg value="UTF-8"/> </bean> </mvc:message-converters> </mvc:annotation-driven> <!--开启spring中的定时任务--> <task:annotation-driven/> <!--开始AOP--> <aop:aspectj-autoproxy/> <!-- 对静态资源文件的访问, 将无法mapping到Controller的path交给default servlet handler处理 --> <mvc:default-servlet-handler/> <!-- 静态资源映射 --> <mvc:resources mapping="/static/**" location="/static/" cache-period="31536000"/> <!-- 定义无Controller的path<->view直接映射 --> <mvc:view-controller path="/" view-name="redirect:${web.view.index}"/> </beans>
4.书写注解类,自定义业务
import com.future.dcwj.common.annotation.ReviewProgressAnnotation;
import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.util.HashMap;
import java.util.Map;
/**
* describe:
*
* @author wangfeixiong
* @date 2018/02/09
*/
@Component
@Aspect
public class ReviewProgressAOP {
private final static Logger LOGGER = Logger.getLogger(ReviewProgressAOP.class);
public static final String SUCESS = "true";
private static final String NO_SUCESS = "false";
public static final String REVIEW_ACTION_PROGRESS= "reviewActionProgress";
@Pointcut("@annotation(com.future.dcwj.common.annotation.ReviewProgressAnnotation)")
public void pointcutName() {
}
/**
* @param joinPoint
*/
@Around("pointcutName()")
public Object introcepter(ProceedingJoinPoint joinPoint) {
MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
ReviewProgressAnnotation progressAnnotation = methodSignature.getMethod().getAnnotation(ReviewProgressAnnotation.class);
String operation = progressAnnotation.value();
StringBuffer key = new StringBuffer();
LOGGER.error(key.toString());
User user = UserUtils.getUser();
if (user != null) {
key.append(user.getId());
}
key = key.append(operation);
LOGGER.info(operation);
try {
Object result = joinPoint.proceed();
map.put(key.toString(), SUCESS);
JedisUtils.mapPut(REVIEW_ACTION_PROGRESS,map);
return result;
} catch (Throwable throwable) {
throwable.printStackTrace();
}
return null;
}
}