CGLIB 之 MethodInterceptor

 

目录

一、什么是CGLIB

二、CGLIB增强

   2.1 代码示例

 2.1.1 权限注解

2.1.2 权限校验

 2.1.3 数赋服务类

2.1.4权限校验代理

2.1.5测试代码

2.1.6 多过滤器优化


一、什么是CGLIB

在学习Spring AOP 的时候我们知道Spring AOP 的实现方式是通过JDK 的动态代理和CGLIB的动态代理实现的,那么什么是CGLIB呢?

       CGLIB其实就是封装了ASM(Java字节码操控框架)了的功能强大,高性能,高质量的Code生成类库。它可以在运行期扩展Java类与实现Java接口。

二、CGLIB增强

    我们常见的就是Enhancer类增强方式。它可以动态生成一个子类使方法可以被拦截;处理实现接口,该类还额可以动态生成父类中非final方法的子类,并提供回调用户自定义拦截器的钩子。原生的和普遍被使用的回调类型是MethodInterceptor ,它在AOP方面实现了环绕通知,也就是说你既可以在调用父类方法之前和之后调用自定义的增强代码。此外,你可以在调用父类方法前修改入参,甚至是根本就不调用父类方法。 虽然,MethodInterceptor 是通用的,足以满足任何拦截需求,但是它往往矫枉过正。为了简单性和性能增加了专门的回调类型 如LazyLoader,经常一个回调在每个拦截器中都没调用,你可以通过CallbackFilter 控制在每个方法上使用哪个回调。有这样一个Service 提供了数据的增删改查功能,使用自定义注解标注每个方法被访问时要求的权限

   2.1 代码示例

       假设有这样一个服务,我们需要针对每个方法进行权限校验,只有有相应权限(ADD,UPDATE,QUERY,DELETE)的用户才可以执行对应的方法。那么如何限制到方法维度呢?为了提升通用性,我们可以使用基于注解的方式解决。

 2.1.1 权限注解

/**
 *
 * @author zhangwei_david
 * @version $Id: permission.java, v 0.1 2015年1月19日 下午8:58:56 zhangwei_david Exp $
 */
@Documented
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Permission {

    String[] value();

}

2.1.2 权限校验

我们现在已经可以在方法上加上注解了那么如何进行方法维度的权限校验呢?我们看看如下代码,

如果方法上有权限控制的注解,我们就判断当前用户的角色是否符合预期。

/**
 *权限工具类
 * @author zhangwei_david
 * @version $Id: AuthUtils.java, v 0.1 2015年1月19日 下午9:14:07 zhangwei_david Exp $
 */
public class AuthUtils {
    /**
     * 判断当前用户角色是否具有当前方法的访问权限
     *
     * @param method
     * @param role
     * @return
     */
    public static boolean isGrantPermission(Method method, String role) {
        String[] roles = null == method.getAnnotation(Permission.class) ? null : method
            .getAnnotation(Permission.class).value();
        if (roles == null || roles.length == 0) {
            return true;
        }
        for (String string : roles) {
            if (string.equals(role)) {
                return true;
            }
        }
        return false;
    }
}

 2.1.3 数赋服务类

在有了注解以及权限判断工具以后,我们来看看这个数据服务类,提供增删改查,同时针对不同的方法进行权限控制,代码如下:

/**
 *数据服务类
 * @author zhangwei_david
 * @version $Id: TableDAO.java, v 0.1 2015年1月19日 下午8:16:14 zhangwei_david Exp $
 */
public class MyService {
    @Permission("ADD")
    public void add() {
        System.out.println("create() is running !");
    }

    @Permission({ "ADD", "QUERY", "UPDATE", "QUERY" })
    public void query() {
        System.out.println("query() is running !");
    }

    @Permission({ "UPDATE" })
    public void update() {
        System.out.println("update() is running !");
    }

    @Permission("DELETE")
    public void delete() {
        System.out.println("delete() is running !");
    }
}

2.1.4权限校验代理

       我们已经有基于注解的权限控制服务类,也有权限校验的辅助工具,那么什么时候执行权限校验呢?直接调用MyService似乎是无法进行权限控制的。下面就需要CGLIB出场了

首先定义一个MethodInterceptor来做方法拦截处理

/**
 *安全代理类
 * @author zhangwei_david
 * @version $Id: AuthProxy.java, v 0.1 2015年1月19日 下午8:20:36 zhangwei_david Exp $
 */
public class AuthProxy implements MethodInterceptor {

    private String role;

    /**
     * @see net.sf.cglib.proxy.MethodInterceptor#intercept(java.lang.Object, java.lang.reflect.Method, java.lang.Object[], net.sf.cglib.proxy.MethodProxy)
     */
    public Object intercept(Object arg0, Method method, Object[] arg2, MethodProxy arg3)
                                                                                        throws Throwable {
        if (AuthUtils.isGrantPermission(method, role)) {
            return arg3.invokeSuper(arg0, arg2);
        }
        System.out.println("expected role is "
                + Arrays.toString(method.getAnnotation(Permission.class).value())
                + " but now is " + role);
        return null;
    }

    public AuthProxy(String role) {
        super();
        this.role = role;
    }

}

 在MethodInterceptor基础上使用Enhancer()Myservice 进行增强。

/**
 *
 * @author zhangwei_david
 * @version $Id: TableDAOFactory.java, v 0.1 2015年1月19日 下午8:16:47 zhangwei_david Exp $
 */
public class DAOFactory {

    public static MyService getInstance(AuthProxy authProxy) {
        Enhancer eh = new Enhancer();
        eh.setSuperclass(MyService.class);
        eh.setCallback(authProxy);
        return (MyService) eh.create();
    }
}

2.1.5测试代码

/**
 *
 * @author zhangwei_david
 * @version $Id: Client.java, v 0.1 2015年1月19日 下午8:18:18 zhangwei_david Exp $
 */
public class Client {

    /**
     *
     * @param args
     */
    public static void main(String[] args) {
        MyService tableDAO = DAOFactory.getInstance(new AuthProxy("ADD"));
        tableDAO.add();
        tableDAO.delete();
        tableDAO.update();
        tableDAO.query();
    }

}

 结果是:

create() is running !
expected role is [DELETE] but now is ADD
expected role is [UPDATE] but now is ADD
query() is running !

通过上述结果,我们可以发现现在是符合我们预期的。那有没有什么不足呢?  

发现在AuthUtils判断了一个类是否有权限控制的注解,我们可以想一下如果一个类都没有权限控制为什么还需要进入权限的拦截器中呢?

2.1.6 多过滤器优化

/**
 *
 * @author zhangwei_david
 * @version $Id: TableDAOFactory.java, v 0.1 2015年1月19日 下午8:16:47 zhangwei_david Exp $
 */
public class DAOFactory {

    public static MyService getInstance(AuthProxy authProxy) {
        Enhancer eh = new Enhancer();
        eh.setSuperclass(MyService.class);
        eh.setCallbacks(new Callback[] { authProxy, NoOp.INSTANCE });
        eh.setCallbackFilter(new PermissionControlleFilter());
        return (MyService) eh.create();
    }
}

/**
 *
 * @author zhangwei_david
 * @version $Id: PermissionControlleFilter.java, v 0.1 2015年1月19日 下午10:06:09 zhangwei_david Exp $
 */
public class PermissionControlleFilter implements CallbackFilter {

    /**
     * @see net.sf.cglib.proxy.CallbackFilter#accept(java.lang.reflect.Method)
     */
    public int accept(Method method) {
        if (method.getAnnotation(Permission.class) != null) {
            return 0;
        }
        return 1;
    }

}

这样就是表示如果一个方法中没有使用权限注解标注改方法的权限的化就使用第二个拦截器,第二个拦截器

 NoOp.INSTANCE

是CGLIB预定义的一个空个回调。

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
org.springframework.cglib.proxy.MethodInterceptorCGLIB库中的接口,用于实现方法拦截器,可以在方法调用前后进行某些操作。 使用步骤如下: 1. 实现MethodInterceptor接口,并重写intercept方法。 2. 创建Enhancer对象,用于生成代理类。 3. 设置代理类的父类、接口、方法拦截器等属性。 4. 调用create方法创建代理类。 5. 使用代理类进行方法调用。 示例代码如下: ``` // 实现MethodInterceptor接口 public class MyMethodInterceptor implements MethodInterceptor { @Override public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("before method " + method.getName()); Object result = proxy.invokeSuper(obj, args); System.out.println("after method " + method.getName()); return result; } } // 创建Enhancer对象 Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(UserServiceImpl.class); enhancer.setCallback(new MyMethodInterceptor()); // 创建代理类 UserServiceImpl userService = (UserServiceImpl) enhancer.create(); // 使用代理类调用方法 userService.addUser(new User()); ``` 在上述示例中,我们创建了一个名为MyMethodInterceptor的方法拦截器,并在intercept方法中输出了方法调用前后的日志信息。然后,我们创建了一个Enhancer对象,并设置了代理类的父类和方法拦截器。最后,我们使用Enhancer对象的create方法创建了代理类,并使用代理类调用了addUser方法。在方法调用时,MyMethodInterceptor会被触发,输出方法调用前后的日志信息。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

陈脩

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值