Spring的AOP采用了动态代理技术,其中有基于JDK的Proxy的代理和基于CGLIB的代理。
下面介绍一下CGLIB的代理技术。
所谓代理,我的理解就是,如果你想要访问一个类的方法,比如Class Hello类的init()方法,按照普通的操作,我们通常是这样的Hello he = new Hello();he.init(); 这是最直接的访问方式。那么代理就是不直接访问,而是通过代理来访问。CGLIB的代理技术和jdk的还有不同,jdk只能代理接口,而cglib可以代理普通的类。其实cglib是通过底层的字节码技术动态的生成被代理类的一个子类来实现代理的。
下面看一段代码吧,代码也是抄录了一位网友的,嘿嘿。。。。
public class InfoManager {
// 模拟查询操作
public void query() {
System.out.println("query");
}
// 模拟创建操作
public void create() {
System.out.println("create");
}
// 模拟更新操作
public void update() {
System.out.println("update");
}
// 模拟删除操作
public void delete() {
System.out.println("delete");
}
}
这是一个普通的dao类,定义了CRUD的基本操作。
public class InfoManagerFactory {
private static InfoManager manger = new InfoManager();
/**
* 创建原始的InfoManager
*
* @return
*/
public static InfoManager getInstance() {
return manger;
}
}
工厂类,用于产生dao类的实例。其实你不用工厂也没有关系,那就直接new吧。。。。
public class Client {
public static void main(String[] args) {
Client c = new Client();
c.anyonecanManager();
}
/**
* 模拟:没有任何权限要求,任何人都可以操作
*/
public void anyonecanManager() {
System.out.println("any one can do manager");
InfoManager manager = InfoManagerFactory.getInstance();
manager.create();
manager.update();
manager.delete();
manager.query();
}
}
这是主方法,进行一系列的操作。。
这个应用是一个普通的调用,没什么特别的。不过却有一个新的需求,那就是只有一个叫“maurice”的用户登录,才允许对信息进行create,update,delete,query的操作。 拿到这个需求,我们会想到这个干,第一:在InfoManager类中的每个方法里加上一句:if("maurice".equal(username)){},username是作为参数传给方法的。这是个可行的方法。 我们也有第二种方法:那就是在调用方法的时候做总体判断。也是加上那就if。同样可以。
但我们今天要讲的是另外一种方法--代理。新建一个CGLIB代理类:
public class AuthProxy implements MethodInterceptor {
private String name; // 会员登录名
public AuthProxy(String name) {
this.name = name;
}
/**
* 权限校验,如果会员名为:maurice,则有权限做操作,否则提示没有权限
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
if (!"maurice".equals(this.name)) {
System.out.println("AuthProxy:you have no permits to do manager!");
return null;
}
return proxy.invokeSuper(obj, args);
}
}
这个类继承了MethodInterceptor 类,这是cglib操作必须实现的一个接口。在intercept里我们进行了一个权限的判断,没有权限就返回null,有权限才允许方法通过。这就完成了权限的控制。那么如何使用他呢?
在最开始的factory的代码里,我们可以用这种方法获得目标类的对象InfoManager manager = InfoManagerFactory.getInstance();,如果我们不修改getInstance方法,那就和之前没有任何区别。加入了代理后,我们可以这么写getInstance方法:
public static InfoManager getInstance(AuthProxy auth) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(InfoManager.class);
enhancer.setCallback(auth);
return (InfoManager) enhancer.create();
}
奇迹般的,该方法返回了一个InfoManager对象。其实关键的秘密是enhancer.create()方法,他会去构造InfoManager的一个子类,返回的其实是Infomanager的子类的实例。setCallback()方法比较重要,他有一个参数,这个参数就是你定义的代理类的引用。
所以主方法就可以这么改进:
public class Client {
public static void main(String[] args) {
Client c = new Client();
c.anyonecanManager();
}
/**
* 模拟:没有任何权限要求,任何人都可以操作
*/
public void anyonecanManager() {
System.out.println("any one can do manager");
AuthProxy auth = new AuthProxy("maurice1")
InfoManager manager = InfoManagerFactory.getInstance(auth);
manager.create();
manager.update();
manager.delete();
manager.query();
}
}
这样就实现了权限的控制。。。。。