CGLIB基於ASM實現。提供比反射更爲強大的動態特性。使用CGLIB能夠很是方便的實現的動態代理。html
cglib是經過動態的生成一個子類去覆蓋所要代理類的非final方法,並設置好callback,則原有類的每一個方法調用就會轉變成調用用戶定義的攔截方法(interceptors)。java
CGLIB代理相關的經常使用API以下圖所示:web
net.sf.cglib.proxy.Callback接口在CGLIB包中是一個重要的接口,全部被net.sf.cglib.proxy.Enhancer類調用的回調(callback)接口都要繼承這個接口。編程
net.sf.cglib.proxy.MethodInterceptor可以知足任何的攔截(interception )須要。對有些狀況下可能過分。爲了簡化和提升性能,CGLIB包提供了一些專門的回調(callback)類型:數組
CGLIB動態代理的原理就是用Enhancer生成一個原有類的子類,而且設置好callback到proxy, 則原有類的每一個方法調用都會轉爲調用實現了MethodInterceptor接口的proxy的intercept() 函數,如圖ide
在intercept()函數裏,除執行代理類的緣由方法,在原有方法先後加入其餘須要實現的過程,改變原有方法的參數值,便可以實現對原有類的代理了。這似於AOP中的around advice。函數
當對代理中全部方法的調用時,都會轉向MethodInterceptor類型的攔截(intercept)方法,在攔截方法中再調用底層對象相應的方法。下面咱們舉個例子,假設你想對目標對象的全部方法調用進行權限的檢查,若是沒有通過受權,就拋出一個運行時的異常。工具
net.sf.cglib.proxy.MethodInterceptor接口是最通用的回調(callback)類型,它常常被基於代理的AOP用 來實現攔截(intercept)方法的調用。性能
MethodInterceptor接口只定義了一個方法:學習
public Object intercept(Object object, java.lang.reflect.Method method, Object[] args, MethodProxy proxy) throws Throwable;
參數Object object是被代理對象,不會出現死循環的問題。
參數java.lang.reflect.Method method是java.lang.reflect.Method類型的被攔截方法。
參數Object[] args是被被攔截方法的參數。
參數MethodProxy proxy是CGLIB提供的MethodProxy 類型的被攔截方法。
注意:
一、若原方法的參數存在基本類型,則對於第三個參數Object[] args會被轉化成類的類型。如原方法的存在一個參數爲int,則在intercept方法中,對應的會存在一個Integer類型的參數。
二、若原方法爲final方法,則MethodInterceptor接口沒法攔截該方法。
class MethodInterceptorImpl implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before invoke " + method);
Object result = proxy.invokeSuper(obj, args);
System.out.println("After invoke" + method);
return result;
}
}
Object result=proxy.invokeSuper(o,args); 表示調用原始類的被攔截到的方法。這個方法的先後添加須要的過程。在這個方法中,咱們能夠在調用原方法以前或以後注入本身的代碼。
因爲性能的緣由,對原始方法的調用使用CGLIB的net.sf.cglib.proxy.MethodProxy對象,而不是反射中通常使用java.lang.reflect.Method對象。
net.sf.cglib.proxy.Enhancer中有幾個經常使用的方法:
注意:在參數中,基本類型應被轉化成類的類型。
基本代碼:
public Object createProxy(Class targetClass) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(targetClass);
enhancer.setCallback(new MethodInterceptorImpl ());
return enhancer.create();
}
createProxy方法返回值是targetClass的一個實例的代理。
例1:使用CGLIB生成代理的基本使用。
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class TestMain {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Cglib.class);
enhancer.setCallback(new HelloProxy());
Cglib cglibProxy = (Cglib)enhancer.create();
cglibProxy.cglib();
}
}
class Cglib{
public void cglib(){
System.out.println("CGLIB");
}
}
class HelloProxy implements MethodInterceptor{
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Hello");
Object object = proxy.invokeSuper(obj, args);
System.out.println("Powerful!");
return object;
}
}
輸出內容:
Hello
CGLIB
Powerful!
例2:使用CGLIB建立一個Dao工廠,並展現一些基本特性。
public interface Dao {
void add(Object o);
void add(int i);
void add(String s);
}
public class DaoImpl implements Dao {
@Override
public void add(Object o) {
System.out.println("add(Object o)");
}
@Override
public void add(int i) {
System.out.println("add(int i)");
}
public final void add(String s) {
System.out.println("add(String s)");
}
}
public class Proxy implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("攔截前...");
// 輸出參數類型
for (Object arg : args) {
System.out.print(arg.getClass() + ";");
}
Object result = proxy.invokeSuper(obj, args);
System.out.println("攔截後...");
return result;
}
}
public class DaoFactory {
public static Dao create() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(DaoImpl.class);
enhancer.setCallback(new Proxy());
Dao dao = (Dao) enhancer.create();
return dao;
}
}
public class TestMain {
public static void main(String[] args) {
Dao dao = DaoFactory.create();
dao.add(new Object());
dao.add(1);
dao.add("1");
}
}
輸出內容:
攔截前...
class java.lang.Object;add(Object o)
攔截後...
攔截前...
class java.lang.Integer;add(int i)
攔截後...
add(String s)
net.sf.cglib.proxy.CallbackFilter有選擇的對一些方法使用回調。
CallbackFilter能夠實現不一樣的方法使用不一樣的回調方法。因此CallbackFilter稱爲"回調選擇器"更合適一些。
CallbackFilter中的accept方法,根據不一樣的method返回不一樣的值i,這個值是在callbacks中callback對象的序號,就是調用了callbacks[i]。
import java.lang.reflect.Method;
import net.sf.cglib.proxy.Callback;
import net.sf.cglib.proxy.CallbackFilter;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import net.sf.cglib.proxy.NoOp;
public class CallbackFilterDemo {
public static void main(String[] args) {
// 回調實例數組
Callback[] callbacks = new Callback[] { new MethodInterceptorImpl(), NoOp.INSTANCE };
// 使用enhancer,設置相關參數。
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(User.class);
enhancer.setCallbacks(callbacks);
enhancer.setCallbackFilter(new CallbackFilterImpl());
// 產生代理對象
User proxyUser = (User) enhancer.create();
proxyUser.pay(); // 買
proxyUser.eat(); // 吃
}
/**
* 回調過濾器類。
*/
private static class CallbackFilterImpl implements CallbackFilter {
@Override
public int accept(Method method) {
String methodName = method.getName();
if ("eat".equals(methodName)) {
return 1; // eat()方法使用callbacks[1]對象攔截。
} else if ("pay".equals(methodName)) {
return 0; // pay()方法使用callbacks[0]對象攔截。
}
return 0;
}
}
/**
* 自定義回調類。
*/
private static class MethodInterceptorImpl implements MethodInterceptor {
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("Before invoke " + method);
Object result = proxy.invokeSuper(obj, args); // 原方法調用。
System.out.println("After invoke" + method);
return result;
}
}
}
class User {
public void pay() {
System.out.println("買東西");
}
public void eat() {
System.out.println("吃東西");
}
}
輸出結果:
Before invoke public void sjq.cglib.filter.User.pay()
pay()
After invokepublic void sjq.cglib.filter.User.pay()
eat()
CGLIB的代理包net.sf.cglib.proxy.Mixin類提供對Minix編程的支持。Minix容許多個對象綁定到一個單個的大對象上。在代理中對方法的調用委託到下面相應的對象中。 這是一種將多個接口混合在一塊兒的方式, 實現了多個接口。
Minix是一種多繼承的替代方案, 很大程度上解決了多繼承的不少問題, 實現和理解起來都比較容易。
import net.sf.cglib.proxy.Mixin;
public class MixinDemo {
public static void main(String[] args) {
//接口數組
Class<?>[] interfaces = new Class[] { MyInterfaceA.class, MyInterfaceB.class };
//實例對象數組
Object[] delegates = new Object[] { new MyInterfaceAImpl(), new MyInterfaceBImpl() };
//Minix組合爲o對象。
Object o = Mixin.create(interfaces, delegates);
MyInterfaceA a = (MyInterfaceA) o;
a.methodA();
MyInterfaceB b = (MyInterfaceB) o;
b.methodB();
System.out.println("\r\n 輸出Mixin對象的結構...");
Class clazz = o.getClass();
Method[] methods = clazz.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
System.out.println(methods[i].getName());
}
System.out.println(clazz);
}
}
interface MyInterfaceA {
public void methodA();
}
interface MyInterfaceB {
public void methodB();
}
class MyInterfaceAImpl implements MyInterfaceA {
@Override
public void methodA() {
System.out.println("MyInterfaceAImpl.methodA()");
}
}
class MyInterfaceBImpl implements MyInterfaceB {
@Override
public void methodB() {
System.out.println("MyInterfaceBImpl.methodB()");
}
}
輸出結果:
MyInterfaceAImpl.methodA()
MyInterfaceBImpl.methodB()
輸出Mixin對象的結構...
methodA
methodB
newInstance
class sjq.cglib.mixin.MyInterfaceA$$MixinByCGLIB$$d1f6261a
package sjq.cglib.bean.copy;
import net.sf.cglib.beans.BeanCopier;
public class PropertyCopyDemo {
public static void main(String[] args) {
//兩個對象
Other other = new Other("test", "1234");
Myth myth = new Myth();
System.out.println(other);
System.out.println(myth);
//構建BeanCopier,並copy對象的屬性值。
BeanCopier copier = BeanCopier.create(Other.class, Myth.class, false);
copier.copy(other, myth, null);
System.out.println(other);
System.out.println(myth);
}
}
class Other {
private String username;
private String password;
private int age;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public Other(String username, String password) {
super();
this.username = username;
this.password = password;
}
@Override
public String toString() {
return "Other: " + username + ", " + password + ", " + age;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
class Myth {
private String username;
private String password;
private String remark;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "Myth: " + username + ", " + password + ", " + remark;
}
public void setRemark(String remark) {
this.remark = remark;
}
public String getRemark() {
return remark;
}
}
運行結果以下:
Other: test, 1234, 0
Myth: null, null, null
Other: test, 1234, 0
Myth: test, 1234, null
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import net.sf.cglib.beans.BeanGenerator;
import net.sf.cglib.beans.BeanMap;
/**
*動態實體bean
*/
public class CglibBean {
/**
* 實體Object
*/
public Object object = null;
/**
* 屬性map
*/
public BeanMap beanMap = null;
public CglibBean() {
super();
}
@SuppressWarnings("unchecked")
public CglibBean(Map<String, Class> propertyMap) {
this.object = generateBean(propertyMap);
this.beanMap = BeanMap.create(this.object);
}
/**
* 給bean屬性賦值
* @param property屬性名
* @param value值
*/
public void setValue(String property, Object value) {
beanMap.put(property, value);
}
/**
* 經過屬性名獲得屬性值
* @param property屬性名
*/
public Object getValue(String property) {
return beanMap.get(property);
}
/**
* 獲得該實體bean對象。
*/
public Object getObject() {
return this.object;
}
/**
* 生成Bean
* @param propertyMap
* @return
*/
@SuppressWarnings("unchecked")
private Object generateBean(Map<String, Class> propertyMap) {
BeanGenerator generator = new BeanGenerator();
Set keySet = propertyMap.keySet();
for (Iterator i = keySet.iterator(); i.hasNext();) {
String key = (String) i.next();
generator.addProperty(key, (Class) propertyMap.get(key));
}
return generator.create();
}
}
測試並使用動態Bean
import java.lang.reflect.Method;
import java.util.HashMap;
/**
* Cglib測試類
*/
public class CglibTest {
@SuppressWarnings("unchecked")
public static void main(String[] args) throws ClassNotFoundException {
// 設置類成員屬性
HashMap<String, Class> propertyMap = new HashMap<String, Class>();
propertyMap.put("id", Class.forName("java.lang.Integer"));
propertyMap.put("name", Class.forName("java.lang.String"));
propertyMap.put("address", Class.forName("java.lang.String"));
// 生成動態Bean
CglibBean bean = new CglibBean(propertyMap);
// 給Bean設置值
bean.setValue("id", new Integer(123));
bean.setValue("name", "454");
bean.setValue("address", "789");
// 從Bean中獲取值,固然了得到值的類型是Object
System.out.println(">>id=" + bean.getValue("id"));
System.out.println(">>name=" + bean.getValue("name"));
System.out.println(">>address=" + bean.getValue("address"));// 得到bean的實體
Object object = bean.getObject();
// 經過反射查看全部方法名
Class clazz = object.getClass();
Method[] methods = clazz.getDeclaredMethods();
for (int i = 0; i < methods.length; i++) {
System.out.println(methods[i].getName());
}
}
}
輸出:
>>id=123
>>name=454
>>address=789
setId
getAddress
getName
getId
setName
setAddress
class net.sf.cglib.empty.Object$$BeanGeneratorByCGLIB$$1d39cfaa
本篇學習文檔參考於:
http://jnb.ociweb.com/jnb/jnbNov2005.html
http://wenku.baidu.com/view/3f92297c27284b73f24250b9.html
http://www.cnblogs.com/icejoywoo/
http://www.blogjava.net/calvin/archive/2005/11/28/21741.html
http://m635674608.iteye.com/blog/1435221等其餘高手博客提供的資料。