SpringBoot使用AOP(动态代理)
<!--cglib动态代理-->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.12</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
<version>2.1.7.RELEASE</version>
</dependency>
- 目标target(需要被增强的接口)
//目标target
public interface UserService {
void login(String username, String password);
void regist();
void search();
void update();
}
- 接口实现
/**
* @Description
* @Author zhoumm
* @Version V1.0.0
* @Since 1.0
* @Date 2019-08-24
*/
@Service
public class UserServiceImpl implements UserService{
@Override
public void login(String username, String password) {
System.out.println ("登录");
}
@Override
public void regist() {
System.out.println ("注册");
}
@Override
public void search() {
System.out.println ("userService search...");
}
@Override
public void update() {
System.out.println ("update...");
}
}
- 代理增强类
/**
* @Description 代理增强类
* @Author
* @Version V1.0.0
* @Since 1.0
* @Date 2019-08-25
*/
@Component
@Aspect //标识为一个切面供容器读取
public class UserServiceHelper {
@Before("execution(* com.mmz.tkp.controller.aoptest.UserService.s*(..))")
public void before(){
System.out.println ("前置通知。。。");
}
@AfterReturning(value="execution(* com.mmz.tkp.controller.aoptest.UserService.s*(..))")
public void afterReturning(){
System.out.println ("后置通知。。。");
}
@Around("execution(* com.mmz.tkp.controller.aoptest.UserService.s*(..))")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println ("环绕前。。。");
Object value = pjp.proceed();
System.out.println (value);
System.out.println ("环绕后。。。");
}
@After("execution(* com.mmz.tkp.controller.aoptest.UserService.s*(..))")
public void after(){
System.out.println ("最终通知。。。");
}
@AfterThrowing(value="execution(* *.s*(..))",throwing="ex")
public void afterThrowing(JoinPoint jp,Throwable ex){
System.out.println ("异常抛出通知" + ex);
}
@Pointcut("execution(* com.mmz.tkp.controller.aoptest.UserService.search(..))")
public void mypointcut(){}
@Pointcut("execution(* com.mmz.tkp.controller.aoptest.UserService.update(..))")
public void mypointcut1(){}
//使用@Pointcut来声明切点,避免在每个通知中定义切点
@Before("mypointcut()||mypointcut1()")
public void before1(){
System.out.println ("前置通知。。。。");
}
}
- JDK动态代理工厂类
/**
* @Description JDK动态代理工厂类
* 在运行期 ,在JVM内部动态生成class字节码对象(Class对象)
* Jdk动态代理只针对于接口操作
* @Author
* @Version V1.0.0
* @Since 1.0
* @Date 2019-08-24
*/
public class JDKProxyFactory implements InvocationHandler {
//目标对象
private Object target;
public JDKProxyFactory(Object target) {
this.target = target;
}
//使用Proxy创建代理对象
public Object createProxy(){
//目标类的类加载器对象
ClassLoader classLoader = target.getClass().getClassLoader();
//目标类的实现接口的Class[]
Class<?>[] interfaces = target.getClass().getInterfaces();
//当前对象需实现InvocationHandler接口
return Proxy.newProxyInstance(classLoader,interfaces,this);
}
/**
*
* @param proxy 代理对象,一般不用
* @param method 方法对象
* @param args 方法参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在调用目标对象方法前,统一做一些其他操作,即功能增强
System.out.println ("例如:日志操作......");
return method.invoke(target,args);
}
}
- CGLIB动态代理
/**
* @Description CGLIB动态代理
* CGLIB(Code Generation Library)是一个开源项目
* 是一个强大的,高性能,高质量的Code生成类库,它可以在运行期扩展Java类与实现Java接口。
* CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类
*
* 可以为没有实现接口的类去做代理,也可以为实现接口的类去做代理。
*
* spring采用的是哪一种动态机制:
* 如果目标对象,有接口,优先使用jdk动态代理
* 如果目标对象,无接口,使用cglib动态代理。
* @Author zhoumm
* @Version V1.0.0
* @Since 1.0
* @Date 2019-08-24
*/
public class CglibProxyFactory implements MethodInterceptor {
//目标对象
private Object target;
public CglibProxyFactory(Object target) {
this.target = target;
}
//创建代理对象
public Object createProxy(){
//1.创建Enhancer
Enhancer enhancer = new Enhancer();
//2.传递目标对象Class
enhancer.setSuperclass(target.getClass());
//3.设置回调操作(相当于InvocationHandler)
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
//在调用目标对象方法前,统一做一些其他操作,即功能增强
System.out.println ("例如:日志操作......");
return method.invoke(target,args);
}
}
- controller 代理测试
@Api(value = "aop", description = "面向切面编程")
@RestController
@RequestMapping("/kpt/aop")
@Slf4j
@Validated
public class AopBackGroundController {
@Autowired
private UserService userService;
@ApiOperation(value = "JDK动态代理测试", httpMethod = "GET")
@RequestMapping(value = "/jdkproxy", method = RequestMethod.GET)
public void testJDKProxy(){
//JDK动态代理
userService.login("zz","123456");
System.out.println ("--------------JDK动态代理------------");
JDKProxyFactory jdkProxyFactory = new JDKProxyFactory(userService);
UserService userServiceProxy = (UserService)jdkProxyFactory.createProxy();
userServiceProxy.login("zz","123456");
}
@ApiOperation(value = "CGLIB动态代理测试", httpMethod = "GET")
@RequestMapping(value = "/cglibproxy", method = RequestMethod.GET)
public void testCGLIBProxy(){
//CGLIB动态代理
userService.regist();
System.out.println ("--------------CGLIB动态代理------------");
CglibProxyFactory cglibProxyFactory = new CglibProxyFactory(userService);
UserService userServiceProxy = (UserService)cglibProxyFactory.createProxy();
userServiceProxy.regist();
}
@ApiOperation(value = "AspectJ代理测试", httpMethod = "GET")
@RequestMapping(value = "/aspectJproxy", method = RequestMethod.GET)
public void testAspectJ(){
//com.mmz.tkp.controller.aoptest.UserServiceHelper
userService.search();
}
@ApiOperation(value = "切点通知测试", httpMethod = "GET")
@RequestMapping(value = "/aspectJproxy", method = RequestMethod.GET)
public void testPointcutAdvice(){
//com.mmz.tkp.controller.aoptest.UserServiceHelper
userService.search();
}
}