2013年8月2日星期五

Another realization of AOP

 

we all know, to achieve dynamic proxy AOP, but it has a drawback, is that all the proxied object must implement an interface, otherwise it will report an exception. So if the proxy object that does not implement the interface, how to achieve AOP do? Of course, to be able to use CGlib can be achieved.

 

1, what is the CGlib

 

CGlib is a powerful, high-performance, high-quality Code generation library. It can be expanded at runtime Java classes and implement Java interfaces. However, these practical function is provided by asm, asm then what is? Java bytecode manipulation framework, specifically what we can check the Internet, after all, we are here to discuss is the cglib, cglib is encapsulated asm, asm simplify the operation, to achieve a dynamic run-time to generate a new class. and we may also feel it's powerful, now tell you. actually CGlib for the spring aop provides an implementation of the underlying; to hibernate dynamically generated using cglib VO / PO (interface layer objects).

 

Its principle is to use Enhancer to generate a subclass of the original, and set callback, then the original class into each method invocation call MethodInterceptor interface proxy implements the intercept () function:
public Object intercept (Object o, Method method, Object [] args, MethodProxy proxy)
in the intercept () function, you You can perform Object result = proxy.invokeSuper (o, args); to perform the original function, adding their own things before and after implementation, change its parameters, it can deceive, do something else entirely. To put it plainly, is the AOP in the around advice.

 

2, how to use the CGlib

 

For example: For example, the DAO layer has on the table to add, delete, change, check operation, if you want the original DAO layer to add, delete, change, increase access control, then modify the code is very painful . So you can use AOP to achieve. But do not use DAO layer interfaces, dynamic proxy is unavailable. This time CGlib is a good choice.

 

TableDao.java:

 
  
 1 package com.cglib; 
2
3 public class TableDao {
4 public void create(){
5 System.out.println("create() is running...");
6 }
7 public void delete(){
8 System.out.println("delete() is running...");
9 }
10 public void update(){
11 System.out.println("update() is running...");
12 }
13 public void query(){
14 System.out.println("query() is running...");
15 }
16 }
 
 

 

implements MethodInterceptor interface AuthProxy.java: methods used to intercept method to increase access permission control, this only allows access to Joe Smith.

 
  
 1 package com.cglib; 
2
3 import java.lang.reflect.Method;
4
5 import net.sf.cglib.proxy.MethodInterceptor;
6 import net.sf.cglib.proxy.MethodProxy;
7 //方法拦截器
8 public class AuthProxy implements MethodInterceptor {
9 private String userName;
10 AuthProxy(String userName){
11 this.userName = userName;
12 }
13 //用来增强原有方法
14 public Object intercept(Object arg0, Method arg1, Object[] arg2,
15 MethodProxy arg3) throws Throwable {
16 //权限判断
17 if(!"张三".equals(userName)){
18 System.out.println("你没有权限!");
19 return null;
20 }
21 return arg3.invokeSuper(arg0, arg2);
22 }
23 }
 
 

TableDAOFactory.java: to create a subclass of TableDao factory class

 
  
 1 package com.cglib; 
2
3 import net.sf.cglib.proxy.Callback;
4 import net.sf.cglib.proxy.Enhancer;
5 import net.sf.cglib.proxy.NoOp;
6
7 public class TableDAOFactory {
8 private static TableDao tDao = new TableDao();
9 public static TableDao getInstance(){
10 return tDao;
11 }
12 public static TableDao getAuthInstance(AuthProxy authProxy){
13 Enhancer en = new Enhancer(); //Enhancer用来生成一个原有类的子类
14 //进行代理
15 en.setSuperclass(TableDao.class);
16 //设置织入逻辑
17 en.setCallback(authProxy);
18 //生成代理实例
19 return (TableDao)en.create();
20 }
21 }
 
 

test class Client.java:

 
  
 1 package com.cglib; 
2
3 public class Client {
4
5 public static void main(String[] args) {
6 // haveAuth();
7 haveNoAuth();
8 }
9 public static void doMethod(TableDao dao){
10 dao.create();
11 dao.query();
12 dao.update();
13 dao.delete();
14 }
15 //模拟有权限
16 public static void haveAuth(){
17 TableDao tDao = TableDAOFactory.getAuthInstance(new AuthProxy("张三"));
18 doMethod(tDao);
19 }
20 //模拟无权限
21 public static void haveNoAuth(){
22 TableDao tDao = TableDAOFactory.getAuthInstance(new AuthProxy("李四"));
23 doMethod(tDao);
24 }
25 }
 
 

This method can be carried out on the DAO layer access control it. But if it needs to change, and make the query method DAO layer so that all users can access, while other methods still have access control, how to achieve it? This can beat us, because we use CGlib. Of course, the easiest way is to modify our approach interceptors, but this would complicate the logic and is not conducive to maintenance. Fortunately CGlib gives us a method filter (CallbackFilter), CallbackFilte be clear that the proxy class in different ways, which was intercepted by the interceptor. Here we have to make a filter used to filter the query method.

 

AuthProxyFilter.java:

 
  
 1 package com.cglib; 
2
3 import java.lang.reflect.Method;
4
5 import net.sf.cglib.proxy.CallbackFilter;
6 import net.sf.cglib.proxy.NoOp;
7
8 public class AuthProxyFilter implements CallbackFilter {
9
10 public int accept(Method arg0) {
11 /*
12 * 如果调用的不是query方法,则要调用authProxy拦截器去判断权限
13 */
14 if(!"query".equalsIgnoreCase(arg0.getName())){
15 return 0; //调用第一个方法拦截器,即authProxy
16 }
17 /*
18 * 调用第二个方法拦截器,即NoOp.INSTANCE,NoOp.INSTANCE是指不做任何事情的拦截器
19 * 在这里就是任何人都有权限访问query方法,所以调用默认拦截器不做任何处理
20 */
21 return 1;
22 }
23
24 }
 
 

as to why returns 0 or 1, comment talk very detailed.

 

at TableDAOFactory.java to add the following method:

 
  
1 public static TableDao getAuthInstanceByFilter(AuthProxy authProxy){   
2 Enhancer en = new Enhancer();
3 en.setSuperclass(TableDao.class);
4 en.setCallbacks(new Callback[]{authProxy,NoOp.INSTANCE}); //设置两个方法拦截器
5 en.setCallbackFilter(new AuthProxyFilter());
6 return (TableDao)en.create();
7 }
 
 

here Notably, en.setCallbacks () method The array parameter in the order the return value is above represent method interceptor, return 0 if using authProxy interceptor, return 1 using NoOp.INSTANCE interceptors, NoOp.INSTANCE is the default method interceptors, what not to do treatment.

 

following in the test class, add the following method: < / span>

 
  
1 //模拟权限过滤器 
2 public static void haveAuthByFilter(){
3 TableDao tDao = TableDAOFactory.getAuthInstanceByFilter(new AuthProxy("张三"));
4 doMethod(tDao);
5 tDao = TableDAOFactory.getAuthInstanceByFilter(new AuthProxy("李四"));
6 doMethod(tDao);
7 }
 
 

in the main method call this method, the program runs The results are as follows:

 

create () is running ...
query () is running ...
update () is running ...
delete () is running ...
You do not have permission!
query () is running ...
You do not have permission!
You do not have permission!

 

In this case, all users on the query methods access rights, while the other method only allows access to Zhang.

 

References: http://llying.iteye.com/blog/220452

 

 

没有评论:

发表评论