首先定义一个注解:
package com.niu.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Created by niuyadong on 2018/5/10.
*/
@Target({ElementType.TYPE, ElementType.METHOD})//注解类型,级别
@Retention(RetentionPolicy.RUNTIME)//运行时注解
public @interface PermissionCheck {
String value() default "";
}
根据这个注解编写一个注解切面:
package com.niu.aspect;
import com.niu.annotation.PermissionCheck;
import com.niu.exception.PermissionCheckException;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
/**
* Created by niuyadong on 2018/5/10.
*/
@Aspect //切面标识
@Component //交给spring管理
public class PermissionAspect {
/**
* 定义一个切入点方法,会拦截含有此注解的方法
*/
@Pointcut("@annotation(com.niu.annotation.PermissionCheck)") //切入点表达式
private void permissionCheck(){} //切入点签名
/**
*在被拦截的方法之前会执行的操作
*/
@Before("permissionCheck();") //相当于 @Before("@annotation(com.niu.annotation.PermissionCheck)")
public void before(JoinPoint joinPoint) throws NoSuchMethodException {
Signature signature = joinPoint.getSignature(); //获取切入点方法签名对象,(在此处应该获取到被拦截的方法)
if(!(signature instanceof MethodSignature)){
throw new PermissionCheckException("签名方法获取异常,终端连接");
}
MethodSignature methodSignature = (MethodSignature) signature; //将签名对象强制转换成方法签名对象
System.out.println(methodSignature.getName());
System.out.println("被代理的对象:" + joinPoint.getTarget()); //getTarget() 获取被代理对象
System.out.println("代理对象自己:" + joinPoint.getThis()); //getThis() 获取代理对象本身
Object target = joinPoint.getTarget();//获取被代理的对象
System.out.println("被代理的类对象:"+target.getClass());
Method method = target.getClass().getMethod(methodSignature.getName(),
methodSignature.getParameterTypes());//根据被代理的类对象获取要执行的方法
PermissionCheck permissionCheck = method.getAnnotation(PermissionCheck.class);//获取该方法的指定注解
System.out.println(permissionCheck.value()); //获取注解的值,然后根据传入的值,执行自己的业务逻辑
}
/**
* 在被拦截的方法之后会执行的操作
*/
@After("permissionCheck();") //相当于 @After("@annotation(com.niu.annotation.PermissionCheck)")
public void after(){
System.out.println("在切入点方法执行之后");
}
}
在切面程序执行过程中会有一些自定义的异常抛出,所以需要设置一个自定义异常(其余可以根据自己需要设置自己的异常):
package com.niu.exception;
/**
* Created by niuyadong on 2018/5/10.
* 自定义签名异常
*/
public class PermissionCheckException extends RuntimeException{
public PermissionCheckException(String exception){
super(exception);
}
}
最后在controller中引用这个注解,就会将自己想要的功能块交给切面处理,代码如下:
package com.niu.controller;
import com.niu.annotation.PermissionCheck;
import com.niu.domain.Girl;
import com.niu.repository.GirlRepository;
import com.niu.service.GirlService;
import org.springframework.validation.BindingResult;
import org.springframework.web.bind.annotation.*;
import javax.annotation.Resource;
import javax.validation.Valid;
import java.util.List;
/**
* Created by niuyadong on 2018/5/9.
*/
@RestController
public class GirlController {
@Resource
private GirlRepository girlRepository;
/**
* 添加一个女生
* @param girl
* @return
*/
@PostMapping(value="/girls")
@PermissionCheck("create:niu")
public Girl createGirl(@Valid Girl girl, BindingResult bindingResult){
if(bindingResult.hasErrors()){
System.out.println(bindingResult.getFieldError().getDefaultMessage());
return null;
}
return girlRepository.save(girl);
}
}
这样就实现了一个基于注解的切面编程,可以用于自定义的事务管理,权限校验等场景。
基于注解的切面实现原理:
注解不会主动执行,只能通过method对象获取注解,然后根据注解做不同的操作。因为切入点在注解上,所以只需要增加一个注解就能够将该功能添加到自己的业务逻辑上。
测试输出结果:
被代理的对象:com.niu.controller.GirlController@294c44b7
代理对象自己:com.niu.controller.GirlController@294c44b7
被代理的类对象:class com.niu.controller.GirlController
create:niu(注解传入的值)
未成年人禁止入内!
在切入点方法执行之后
JoinPoint对象中的getThis()方法和getTarget()方法有什么区别,为什么输出结果一样?
大概理解:百度搜索给出的答案,有其他答案的请在评论中给出,谢谢。