动态代理原理介绍:
SpringBoot使用AOP(动态代理)
- cgllib 需要添加依赖
<!--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(); } }