A, principle
Proxies provide a way to control which target objects to access. It introduces a layer of indirection when accessing objects. Dynamic proxies have been introduced in the JDK since version 1.3 and are often used to create proxies on the fly. Dynamic proxies in the JDK are very simple to use, with the limitation that objects using dynamic proxies must implement one or more interfaces. What if you want to delegate an inherited class that does not implement an interface? Now we can use the CGLIB package.
What is CGLIb
CGLIB is a powerful high-performance code generation package.
-
It is widely used by many AOP frameworks, such as Spring AOP and Dynaop, who provide an interception for their methods.
-
(2) Hibernate uses CGLIB to broker single-ended(many-to-one and one-to-one) associations (lazy fetching of collections is implemented by other mechanisms);
-
(3) EasyMock and jMock are packages that test Java code using mock (MoKE) objects.
Both use CGLIB to create mock (moKE) objects for classes that do not have interfaces.
Third, the principle of
At the bottom of the CGLIB package is the use of a small, fast bytecode processing framework ASM(Java Bytecode Manipulation Framework) to transform bytecode and generate new classes. In addition to the CGLIB package, scripting languages such as Groovy and BeanShell also use ASM to generate Java bytecode. Direct use of ASM is discouraged because it requires that you be familiar with the JVM’s internal structure, including the class file format and instruction set. Therefore, cglib packages depend on ASM packages and need to be imported together. At the bottom of the cglib package is the use of a small and fast Bytecode processing Framework ASM(Java Bytecode Manipulation Framework) to transform Bytecode and generate new classes. In addition to the CGLIB package, scripting languages such as Groovy and BeanShell also use ASM to generate Java bytecode. Direct use of ASM is discouraged because it requires that you be familiar with the JVM’s internal structure, including the class file format and instruction set. Therefore, cglib packages depend on ASM packages and need to be imported together. Cglib Library and ASM Bytecode Framework (Cglib Library and ASM Bytecode Framework)
Spring AOP and Hibernate use both the JDK’s dynamic proxy and the CGLIB package. Spring AOP, if it is not mandatory to use the CGLIB package, defaults to using the JDK’s dynamic proxy to proxy interfaces.
4. Case scenario simulation
- Create a DAO class that operates on Table and provides CRUD methods. BookServiceBean.java
public class BookServiceBean { public void create(){ System.out.println("create() is running !" ); } public void query(){ System.out.println("query() is running !" ); } public void update(){ System.out.println("update() is running !" ); } public void delete(){ System.out.println("delete() is running !" ); }}Copy the code
OK, it provides CRUD methods. Let’s create a DAO factory to generate DAO instances.
private static BookServiceBean service = new BookServiceBean(); private BookServiceFactory() { } public static BookServiceBean getInstance() { return service; }}Copy the code
Create a client to call CRUD methods.
public class Client { public static void main(String[] args) { BookServiceBean service = BookServiceFactory.getInstance(); doMethod(service); } public static void doMethod(BookServiceBean service){ service.create(); service.update(); service.query(); service.delete(); }}Copy the code
OK, we’re done, the CRUD method is completely called. Of course there is nothing about CGlib here. The problem will not simply end. New needs will come. One day, Boss tells us that these methods are not open to users, only “bosses” have access to them. What, are we going to judge every method? Doesn’t that seem like too much of a thing to do? By the way, proxies are probably the best solution. JDK proxies will take care of that. All right, let’s get started. JDK proxies need to implement interfaces, so our DAO class needs to change. Since we don’t want to change the DAO and use the proxy, we’ll pull out CGlib. Just add a method interceptor for permission validation.
import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; import org.apache.log4j.Logger; public class MyCglibProxy implements MethodInterceptor{ private Logger log=Logger.getLogger(MyCglibProxy.class); public Enhancer enhancer = new Enhancer(); private String name; public MyCglibProxy(String name) { this.name = name ; } /** * create a proxy object for this object. 2, Set the callback * nature: Public Object getDaoBean(class CLS) {enhancer.setSuperClass (CLS); enhancer.setCallback(this); return enhancer.create(); } @Override public Object intercept(Object object, Method method, Object[] args, MethodProxy throws Throwable {log.info(" + method.getName()); If (!" Equals (name)){system.out.println (" you don't have permission!" ); return null; } Object result = methodProxy.invokeSuper(object, args); return result; }}Copy the code
Of course, don’t forget to modify our DAO factory to provide an instance generation method using proxies. The above class already provides a generic method for getting proxy instances, and there is no special requirement (see below 3) to get proxy objects in this way.
public static BookServiceBean getProxyInstance(MyCglibProxy myProxy){ Enhancer en = new Enhancer(); // Delegate en.setSuperClass (bookServicebean.class); en.setCallback(myProxy); Return (BookServiceBean)en.create(); }Copy the code
You can take a look at the client implementation. Two methods have been added to verify the permissions of different users
BookServiceBean service = BookServiceFactory.getProxyInstance(new MyCglibProxy("boss"));
service.create();
BookServiceBean service2 = BookServiceFactory.getProxyInstance(new MyCglibProxy("john"));
service2.create();
Copy the code
OK,”boss” is working,” John “is not. See? Is this the end of simple AOP? 3. GRD Boss to lecture again, no, no, no, now except “Boss” other people can not use, now can not do this. You must use the open query function. Ha ha, now can’t elude us, because we use the additional. The easiest way, of course, would be to modify our method interceptors, but that would complicate the logic and make maintenance difficult.
Fortunately, CGlib provides a method filter (CallbackFilter) that makes it clear which interceptor intercepts the different methods in the propped class. Let’s create a filter to filter the Query method.
import java.lang.reflect.Method;
import net.sf.cglib.proxy.CallbackFilter;
public class MyProxyFilter implements CallbackFilter {
@Override
public int accept(Method arg0) {
if(!"query".equalsIgnoreCase(arg0.getName()))
return 0;
return 1;
}
}
Copy the code
Add an instance generation method in the workshop that uses filters
public static BookServiceBean getAuthInstanceByFilter(MyCglibProxy myProxy){
Enhancer en = new Enhancer();
en.setSuperclass(BookServiceBean.class);
en.setCallbacks(new Callback[]{myProxy,NoOp.INSTANCE});
en.setCallbackFilter(new MyProxyFilter());
return (BookServiceBean)en.create();
}
Copy the code
The setCallbacks define the interceptors to use, where noop.instance is provided by CGlib and is actually an interceptor with no operations. They are ordered and must be in the same order as CallbackFilter. The order in which (0/1) is returned. That is, if the query method is called, noop.instance is used for interception.
BookServiceBean service = BookServiceFactory.getProxyInstanceByFilter(new MyCglibProxy("jhon"));
service.create();
BookServiceBean service2 = BookServiceFactory.getProxyInstanceByFilter(new MyCglibProxy("jhon"));
service2.query();
Copy the code
Ok, now “li4” can also use the query method, other methods still do not have permissions. Of course, the implementation of the proxy is not intrusive, and there is no need to force daOs to implement the interface. From blog.csdn.net/xiaohai0504…