spring中的两种aop实现方式jdk动态代理和cglib代理

aop的概念

aop (Aspect Oriented Programming), 直译: 面向侧面编程, 通过 预编译方式 或者 动态代理 实现程序功能的统一维护的一种技术
带来的好处是: 可以对通用的业务逻辑独立, 降低通用逻辑和业务逻辑的耦合, 提高通用逻辑的重用性, 提高开发效率.

主要应用

统一日志记录, 性能统计, 统一授权, 事务处理, 统一异常处理.

jdk动态代理

如何使用

实现利用java.lang.reflect.InvocationHandler接口, 重写其invoke方法为方法批量添加统一业务.

interface UserService {
    void insert(String userName);
}

class UserServiceImpl implements UserService {
    public void insert(String userName) {
        System.out.println("insert " + userName);
    }
}

class UserServiceProxy implements InvocationHandler {
    private Object target;
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        System.out.println("before insert");
        Object result = method.invoke(target, args);
        System.out.println("after insert");
        return result;
    }
    public Object getProxy(Object target) {
        this.target = target;
        return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
    }
}

public class CglibAopDemo { 
    public static void main(String[] args) {
        UserService userService = new UserServiceImpl();
        userService.insert("zhaoxi");// 只输出 insert zhaoxi
        UserServiceProxy proxy = new UserServiceProxy();
        UserService userServiceProxy = (UserService) proxy.getProxy(userService);
        userServiceProxy.insert("zhaoxi");
        //输出: before insert
        //insert zhaoxi
        //after insert
    }
} 
动态代理的代理类生成过程
  1. 根据传入的ClassLoader和接口生成接口代理类的字节码
  2. 将自定义InvocationHandler对象作为代理类构造函数的参数, 传入代理类获取代理类的构造器
  3. 根据构造器来生成代理类的对象实例
jdk动态代理的注意事项
  1. 由于代理类继承了Proxy类, java不支持多继承, 所有只能代理接口, 不能代理类.

cglib代理

如何使用

使用CGLIB库, 实现库中MethodInterceptor 接口为方法添加统一业务
使用时需单独引入CGLIB库

class UserServiceCglib implements MethodInterceptor {
    private Object target;
    public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
        System.out.println("before insert cglib");
        Object result = methodProxy.invokeSuper(o, objects);
        System.out.println("after insert cglib");
        return result;
    }
    public Object getTarget(Object target) {
        this.target = target;
        Enhancer enhancer = new Enhancer();
        enhancer.setSuperclass(this.target.getClass());
        enhancer.setCallback(this);
        return enhancer.create();
    }
}

public static void main(String[] args) {
    UserService userService = new UserServiceImpl();
    UserService userServiceProxy = (UserService) new UserServiceCglib().getTarget(userService);
    userServiceProxy.insert("zhaoxi");
    //输出 before insert cglib
    //insert zhaoxi
    //after insert cglib
}
cglib代理的注意实现
  1. 需要单独引入CGLIB库
  2. 不需要类继承接口, 但是不能将类设置为final, 因为使用继承生成代理.

Spring中的aop概念

定义
  • Joinpoint : 连接点(在哪里), 在什么地方执行 增强操作, spring只支持方法级的连接点.
  • Pointcut : 切点是一组连接点的集合(在哪里干的集合).
    1. 切点表达式介绍 execution(* fun.zhaoxi.aop….(…))
    2. execution() 是表达式的主体
    3. 括号中第一个 * 是方法的返回值, * 代表所有
    4. fun.zhaoxi.aop… 前面是包名的前缀, … 代表子包和孙包中的所有类
    5. . 代表类名和方法名, * 代表所有
    6. (…) 代表方法中的参数, … 代表所有
  • Advice : 增强(干什么), 一般是我们的公共业务.
  • Aspect : 切面(在哪儿干和干什么的集合), SpringAop就是负责操作切面并执行.
    切面类型:
    1. @Before 前置通知
    2. @After 后置通知
    3. @AfterReturning 目标方法执行结束后执行
    4. @AfterThrowing 目标方法异常执行
    5. @Around 环绕通知, 目标方法执行前后都执行
      目标方法正确的执行顺序是
      5 → 1 → target() → 5 → 2 → 3.
切面的示例

下面示例需要引入 spring-core, spring-context, spring-beans, spring-aop, spring-aspects 包
默认使用SDK动态代理, 如果使用CGLIB代理, 需要单独引入CGLIB库.


interface UserService {
    void insert(String userName);
}

@Component
class UserServiceImpl implements UserService {
    public void insert(String userName) {
        System.out.println("insert " + userName);
    }
}

@Component
@Aspect // 切面
class UserServiceAspect { 
    @Pointcut("execution(* fun.zhaoxi.aop.*.*(..))") //切点 参数为切点表达式
    public void pointcut() {
    }
    @Before("pointcut()")
    public void insertBefore() { //增强
        System.out.println("spring aop insert before");
    }
    @After("pointcut()")
    public void insertAfter() { //增强
        System.out.println("spring aop insert after");
    }
    @Around("pointcut()")
    public void insertAround(ProceedingJoinPoint point) throws Throwable { //增强
        System.out.println("spring aop insert around before");
        point.proceed();
        System.out.println("spring aop insert around after");
    }
    @AfterReturning("pointcut()")
    public void insertAfterReturning() { //增强
        System.out.println("spring aop insert afterReturning");
    }
    @AfterThrowing("pointcut()")
    public void insertAfterThrow() { //增强
        System.out.println("spring aop insert afterThrow");
    }
}

//spring-aop.xml: 放入resources文件夹
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd">

    <aop:aspectj-autoproxy/> <!-- 如果要使用cglib代理, 添加 proxy-target-class="true", 需引入 cglib 包 -->
    <context:component-scan base-package="fun.zhaoxi.aop" /><!-- 包名是 service的包名 -->
</beans>

public static void main(String[] args) {
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring-aop.xml");
    UserService userService = applicationContext.getBean(UserService.class);
    userService.insert("zhaoxi");
}

//输出:
// spring aop insert around before
// spring aop insert before
// insert zhaoxi
// spring aop insert around after
// spring aop insert after
// spring aop insert afterReturning

spring的aop总结

aop是spring的核心功能之一, 要玩转spring, 肯定要深入了解.
在spring中 缓存, 错误处理, 事务, 等等功能都有aop的身影, 但是真正能发挥强大功能的是 ioc + aop.

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值