代理设计模式9--使用AOP风格的代理模式
代理模式归根结底,就是在操作真实对象的前后加入新的操作。通常的,在项目中,把业务逻辑代码与公共的事务进行分离。Spring中采用AOP来操作。下面开始介绍如何代理一个Controller类,为Controller加入额外的操作。
第一步:首先是加入依赖包,cglib动态代理的包,Controller类不能为final类哦,因为这个报过一次错。
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjrt</artifactId>
<version>1.8.10</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.10</version>
</dependency>
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>
第二步:编写我们自己的注解。注解的知识还得加强,我自己都写不好。Component是Spring的注解,表明这是一个bean。
import org.springframework.stereotype.Component;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE_PARAMETER, ElementType.METHOD})
@Component
public @interface MyControllerLog {
String description() default "";
//操作类型,增删改查
String methodType() default "";
}
第三步:编写切面
import com.ssi.web.helper.annotation.MyControllerLog;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
@Aspect
@Component
public class MyAspect ...
//定义一个后置返回通知,它表示在切点处 “干什么”
@AfterReturning(value = "pointCutName()")
public void adviceAfter(JoinPoint joinPoint){
LOGGER.info("操作开始,当前执行的方法是:{}",joinPoint.getSignature().getName());
//获取切点方法的方法签名
final MethodSignature methodSignature = (MethodSignature)joinPoint.getSignature();
//获取切点方法的反射对象
final Method targetMethod=methodSignature.getMethod();
//获取方法上的注解对象
MyControllerLog annotionEntity = targetMethod.getAnnotation(MyControllerLog.class);
//拿到注解对象,并获取注解上的信息
String type = annotionEntity.methodType();
LOGGER.info("操作结束,本次操作类型:{}",type);
}
//定义一个切点,它表示 “在哪里” 添加通知
//拦截带有MyControllerLog注解的方法
@Pointcut(value = "@annotation(com.ssi.web.helper.annotation.MyControllerLog)")
public void pointCutName() {
throw new UnsupportedOperationException("不允许调用切点方法");
}
}
第四步:在SpringMVC的配置文件中配置AOP切面的相关信息,SpringBoot中暂时不用配置
<!--注解式AOP,Spring会自动在JDK动态代理和CGLIB之间转换-->
<aop:aspectj-autoproxy proxy-target-class="true"/>
第五步:在Controller层上加入我们的注解
/**
* 去所有文章展示页面,这个是去博客空间的主页
*
* @return 携带上文章的参数,去文章首页
*/
@RequestMapping(value = {URL_ARTICLE_LIST} ,method = {GET})
@MyControllerLog(methodType = "查询")
public ModelAndView home(HttpServletRequest request){
LOGGER.info("enter article list page");
//获取点击量最高的X篇文章
final List<Article> hotArticles = articleService.getArticleByClick(5);
...其它逻辑代码
return new ModelAndView(FWD_ARTICLE_LIST_HOME,map);
}
第六步:启动项目,并在控制台查看效果
看注解,的却是加载了home()方法上。另外,一般这些操作都记录在数据库中。可以在切面类里面,加一个LogService,专门用来保存用户操作的数据。
分割线--------------------------------------------------------------------------------------------