关于cglib代理的概念和原理,这里就不多说了,详细请参考以往的博客:
本篇主要介绍cglib的主要(常用)的api。
一、MethodInterceptor
入门的helloword
import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;
class SampleClass{
public void test(){
System.out.println("test");
}
public void test2(){
System.out.println("test2");
}
}
public class test {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
enhancer.setCallback(new MethodInterceptor(){
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before");
Object res=methodProxy.invokeSuper(o, objects);
System.out.println("after");
return res;
}
});
SampleClass proxy = (SampleClass) enhancer.create();
proxy.test();
proxy.test2();
}
}
输出:
before
test
after
before
test2
after
该种方法将代理SampleClass类的非final的所有成员方法。如果只想代理某个指定的方法,可以实现CallbackFilter接口,如下:
import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;
class SampleClass{
public void test(){
System.out.println("test");
}
public void test2(){
System.out.println("test2");
}
}
public class test {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
CallbackHelper callbackHelper = new CallbackHelper(SampleClass.class, new Class[0]) {
@Override
protected Object getCallback(Method method) {
// 只代理方法名是test的方法
if(method.getName().equals("test")){
return new MethodInterceptor(){
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.print("代理---");
return methodProxy.invokeSuper(o, objects);
}
};
}else{
return NoOp.INSTANCE;
}
}
};
enhancer.setCallbackFilter(callbackHelper);
enhancer.setCallbacks(callbackHelper.getCallbacks());
SampleClass proxy = (SampleClass) enhancer.create();
proxy.test();
proxy.test2();
}
}
输出:
代理---test
test2
这种方法可以指定具体代理某一个方法。
二、InvocationHandler
InvocationHandler可以实现对接口的代理,类似与mybatis,代码中开发者只需要写一个接口和一个xml,mybatis会根据xml的描述信息,帮你生成对应的方法实现,参数的解析、sql的生成、发送、结果集的封装等都不用开发者去写。而其中的原理就是利用了代理模式。
首先定义一个接口,这个接口里有各种返回值类型的方法。
import java.util.List;
public interface TestInterface {
String testString(Integer id);
int testInt(String value);
List testList(Integer age,Integer g);
SampleClass testSampleClass();
}
用代理模式去实现这些方法。实现类交由cglib去动态创建。
import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class test2 {
public static void main(String[] args) {
Class[] classes = {TestInterface.class};
Enhancer enhancer = new Enhancer();
enhancer.setInterfaces(classes);
CallbackHelper callbackHelper = new CallbackHelper(Object.class, classes) {
@Override
protected Object getCallback(Method method) {
// 只代理TestInterface中的方法
if(method.getDeclaringClass() == TestInterface.class){
return new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.print("参数:");
for (Object object : objects) {
System.out.print(object+"\t");
}
System.out.println();
Class<?> returnType = method.getReturnType();
if (returnType == int.class || returnType == Integer.class) {
// 返回值类型是整数类型
return 1;
}else if(returnType == String.class){
// 返回值类型是字符串
return "string";
}else if(returnType == List.class){
// 返回值类型是集合
ArrayList arrayList = new ArrayList();
arrayList.add("11");
return arrayList;
}
// ... 等等
else{
// 自定义类型
return returnType.newInstance();
}
}
};
}else{
// 什么都不做
return NoOp.INSTANCE;
}
}
};
enhancer.setCallbackFilter(callbackHelper);
enhancer.setCallbacks(callbackHelper.getCallbacks());
TestInterface proxy = (TestInterface) enhancer.create();
System.out.println("返回值:"+proxy.testInt("123"));;
System.out.println("返回值:"+proxy.testList(1,1));;
System.out.println("返回值:"+proxy.testString(1));;
System.out.println("返回值:"+proxy.testSampleClass());;
}
}
三、FixedValue
该方法会对所有拦截的方法返回同样的值。
import net.sf.cglib.proxy.*;
import java.lang.reflect.Method;
class SampleClass{
public String test(){
return "test";
}
public String test2(){
return "test2";
}
}
public class test {
public static void main(String[] args) {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(SampleClass.class);
CallbackHelper callbackHelper = new CallbackHelper(SampleClass.class, new Class[0]) {
@Override
protected Object getCallback(Method method) {
// 只代理返回值类型是String类型的方法,如果返回值类型不是String将会抛异常。
if(method.getReturnType()==String.class){
return new FixedValue() {
@Override
public Object loadObject() throws Exception {
return "proxy ...";
}
};
}else{
return NoOp.INSTANCE;
}
}
};
enhancer.setCallbackFilter(callbackHelper);
enhancer.setCallbacks(callbackHelper.getCallbacks());
SampleClass proxy = (SampleClass) enhancer.create();
System.out.println(proxy.test());
System.out.println(proxy.test2());
System.out.println(proxy.toString());
System.out.println(proxy.hashCode());
}
}
输出:
proxy ...
proxy ...
proxy ...
1874154700
返回值是String类型的都返回同样的值。
四、ImmutableBean
不可变的Bean。ImmutableBean允许创建一个原来对象的包装类,这个包装类是不可变的,任何改变底层对象的包装类操作都会抛出IllegalStateException。但是我们可以通过直接操作底层对象来改变包装类对象。
import net.sf.cglib.beans.ImmutableBean;
class SampleBean{
SampleBean(){
}
SampleBean(int id){
this.id = id;
}
private int id;
public int getId(){
return this.id;
}
public void setId(int id){
this.id = id;
}
}
public class test2 {
public static void main(String[] args) {
SampleBean bean = new SampleBean();
bean.setId(1);
SampleBean immutableBean = (SampleBean)ImmutableBean.create(bean);
System.out.println(bean.getId());
System.out.println(immutableBean.getId());
bean.setId(2);
System.out.println(bean.getId());
System.out.println(immutableBean.getId());
immutableBean.setId(3); // 包装类修改将会抛异常
System.out.println(bean.getId());
System.out.println(immutableBean.getId());
}
}
输出:
1
1
2
2
Exception in thread "main" java.lang.IllegalStateException: Bean is immutable
at com.example.SampleBean$$ImmutableBeanByCGLIB$$e23e512b.setId(<generated>)
at com.example.test2.main(test2.java:31)
五、BeanGenerator
cglib提供的一个操作bean的工具,使用它能够在运行时动态的创建一个bean。
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class test2 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
BeanGenerator beanGenerator = new BeanGenerator();
beanGenerator.addProperty("id",int.class);
Object myBean = beanGenerator.create();
Method setter = myBean.getClass().getMethod("setId",int.class);
setter.invoke(myBean,1);
Method getter = myBean.getClass().getMethod("getId");
System.out.println(getter.invoke(myBean));
}
}
动态创建一个类,该类包含一个int类型的id属性,并包含get,set方法。
六、BeanMap
BeanMap类实现了Java Map,将一个bean对象中的所有属性转换为一个String-to-Obejct的Java Map
import net.sf.cglib.beans.BeanMap;
import java.lang.reflect.InvocationTargetException;
class Bean{
int id = 1;
String name = "name";
public int getId(){
return this.id;
}
public String getName(){
return this.name;
}
}
public class test2 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Bean bean = new Bean();
BeanMap beanMap = BeanMap.create(bean);
Object id = beanMap.get("id");
Object name = beanMap.get("name");
System.out.println(id);
System.out.println(name);
}
}
输出:
1
name