SSM笔记(4)——自定义注解与AOP切面

  • 目标

    使用自定义注解标记controller,前端传参调用该controller时,使用切面捕获方法,对传递来的参数添加createTime和createPerson(person从Session中获取),免去在每一个服务类中都要set这两个值

  • 自定义注解

    1. 注解基础

    1.1 注解的形式
      	public @interface Insert{}
    
    1.2 元注解

    可以给注解添加的注解称为“元注解”

    1.2.1 @Retention: 定义注解的保留策略
    属性字段 保留策略
    @Retention(RetentionPolicy.SOURCE) 注解仅存在于源码中,在class字节码文件中不包含
    @Retention(RetentionPolicy.CLASS) 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
    @Retention(RetentionPolicy.RUNTIME) 注解会在class字节码文件中存在,在运行时可以通过反射获取到

    【注】生命周期 SOURCE < CLASS < RUNTIME ,即后者作用域包含前者

    1.2.2 @Target:定义注解的作用目标
    属性字段 作用目标
    @Target(ElementType.TYPE) 接口、类、枚举、注解
    @Target(ElementType.FIELD) 字段、枚举的常量
    @Target(ElementType.METHOD) 方法
    @Target(ElementType.PARAMETER) 方法参数
    @Target(ElementType.CONSTRUCTOR) 构造函数
    @Target(ElementType.LOCAL_VARIABLE) 局部变量
    @Target(ElementType.ANNOTATION_TYPE) 注解
    @Target(ElementType.PACKAGE)
    1.2.3 @Document:说明该注解将被包含在javadoc中
    1.2.4 @Inherited:说明子类可以继承父类中的该注解

    2. 自定义注解

    	@Target(ElementType.METHOD)
    	@Retention(RetentionPolicy.RUNTIME)
    	@Documented
    	public @interface Insert {
    	}
    

    自定义一个Insert注解,用于添加在controller方法上,生命周期为RUNTIME,用于识别是数据插入操作

  • AOP切面

    1. AOP基础

    1.1 注解基础
    1.1.1 通知
    属性字段 作用域
    @Before 在方法调用之前调用通知
    @After 在方法完成之后调用通知,无论方法执行成功与否
    @AfterReturning 在方法执行成功之后调用通知
    @AfterThrowing 在方法抛出异常后进行通知
    @Around 通知包裹了被通知的方法,在被通知的方法调用之前和调用之后执行自定义的行为
    1.1.2 连接点
    • 连接点是一个应用执行过程中能够插入一个切面的点。
    • 连接点可以是调用方法时、抛出异常时、甚至修改字段时
    1.1.3 切点
    • 切点定义了AOP执行的位置
    • 切点是连接点的集合,通常使用正则表达式匹配多个连接点
    • 在SpringAOP中定义切点(使用AspectJ的切点表达式)
    指示器 作用域
    arg () 限制连接点的指定参数为指定类型的执行方法
    @args () 限制连接点匹配参数由指定注解标注的执行方法
    execution () 用于匹配连接点的执行方法
    this () 限制连接点匹配 AOP 代理的 Bean 引用为指定类型的类
    target () 限制连接点匹配特定的执行对象,这些对象对应的类要具备指定类型注解
    within() 限制连接点匹配指定类型
    @within() 限制连接点匹配指定注释所标注的类型
    @annotation 限制匹配带有指定注释的连接点
    1.1.4 切面
    • 切面是通知和切点的集合,定义了AOP执行什么和在哪执行
    1.1.5 引入
    • 引入允许我们向现有的类中添加方法或属性
    1.1.6 织入

    2. 自定义 AOP

@Component
@Aspect
public class SQLOperateAspect {
	//设置切点为@Insert标注的方法
	 @Before(value="@annotation(com.fzu.oqn.Insert)")
	 public void dofore(JoinPoint jp) {			 
         try {
         	 //获取方法入参对象
        	 Object[] objects = jp.getArgs();
        	 //获取入参对象的setCreateTime方法
        	 Method setCreateTime = objects[0].getClass().getMethod("setCreateTime", java.util.Date.class);
        	 //获取入参对象的setCreatePerson方法
        	 Method setCreatePerson = objects[0].getClass().getMethod("setCreatePerson", java.lang.String.class);
        	 //获取session对象的getAttribute方法
        	 Method session_getAttribute = objects[1].getClass().getMethod("getAttribute", java.lang.String.class);
        	 //通过反射获得Session对象中的信息
        	 User user = (User)session_getAttribute.invoke(objects[1], "loginUser");
        	 //通过反射操作函数赋值
        	 setCreateTime.invoke(objects[0], new Date());
        	 setCreatePerson.invoke(objects[0], user.getUserName());
		} catch (SecurityException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalArgumentException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (NoSuchMethodException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (InvocationTargetException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	 }
}
2.1 JoinPoint 对象
方法名 功能
Signature getSignature(); 获取封装了署名信息的对象,在该对象中可以获取到目标方法名,所属类的Class等信息
Object[] getArgs(); 获取传入目标方法的参数对象
Object getTarget(); 获取被代理的对象
Object getThis(); 获取代理对象
  • 使用

@RequestMapping(value="/publishPaper",method= RequestMethod.POST)
	@Insert
	public ResponseMessage publishPaper(@RequestBody QuestionnairePublishVO questionnairePublishVO,HttpSession session) {
		User user = (User)session.getAttribute("loginUser");
		return myPapersService.publishPaper(questionnairePublishVO);
	}

在Controller上添加@Insert注解,调用该方法时AOP会进行拦截,获取第二个参数Session中的登陆者信息,赋值给第一个参数questionnairePublishVO中的createTime和createPerson属性

你可能感兴趣的:(SSM)