1.JDK代理
动态的由java提供的api在内存中构建字节码类对象完成的动态代理.
使用JDK代理方式动态创建对象时,对象需要声明接口并且实现接口;
1.1声明接口:
package yzr.dyn_jdk;
public interface IPerson {
void SayHello();
}
1.2 声明对象,并且实现接口:
package yzr.dyn_jdk;
public class PersonImpl implements IPerson {
private String name;
@Override
public void SayHello() {
System.out.println("Hello "+this.name);
}
public PersonImpl(){}
public PersonImpl(String name){this.name=name;}
}
1.3实现自己的InvocationHandler类
package yzr.dyn_jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
public class MyInvocationHandler implements InvocationHandler {
private Object target;
public MyInvocationHandler(){
super();
}
public MyInvocationHandler(Object target){
super();
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args){
Object Result=null;
try {
Result=method.invoke(target, args);
} catch (Exception e) {
e.printStackTrace();
}
return Result;
}
}
1.4得到代理对象并且调用
package yzr.dyn_jdk;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;
public class TestUnit {
public static void main(String[] args) {
IPerson LYF=new PersonImpl("yzr");
InvocationHandler handler=new MyInvocationHandler(LYF);
IPerson LYFProxy = (IPerson)Proxy.newProxyInstance(
LYF.getClass().getClassLoader(),
LYF.getClass().getInterfaces(),
handler);
LYFProxy.SayHello();
}
}
使用JDK代理的方式动态创建对象时,和使用new关键字(或者反射)创建对象的不同在于,调用对象的方法的时候,可以加入额外的逻辑代码,比如:
@Override
public Object invoke(Object proxy, Method method, Object[] args){
Object Result=null;
try {
System.out.println("调用方法之前:");
Result=method.invoke(target, args);
System.out.println("调用方法之后:");
} catch (Exception e) {
e.printStackTrace();
}
return Result;
}
但是不方便的地方是使用JDK代理这方式要求声明接口,实现接口的对象才能被动态代理生成,所以下面使用cglib代理动态创建对象:
2.cglib代理
需要三个jar包: asm-3.3.1.jar cglib-2.2.jar cglib-nodep-2.2.jar
2.1声明对象
package yzr.dyn_cglib;
public class PersonImpl {
private String name;
public void SayHello() {
System.out.println("Hello "+this.name);
}
public PersonImpl(){}
public PersonImpl(String name){this.name=name;}
}
2.2 实现MethodInterceptor接口
package yzr.dyn_cglib;
import java.lang.reflect.Method;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
public class CglibProxy implements MethodInterceptor {
@Override
public Object intercept(Object arg0, Method arg1, Object[] arg2,
MethodProxy arg3) throws Throwable {
System.out.println(arg1.getName());
System.out.println("调用方法之前");
Object result=arg3.invokeSuper(arg0, arg2);
System.out.println("调用方法之之后");
return result;
}
}
2.3动态获取对象
package yzr.dyn_cglib;
import yzr.dyn_jdk.PersonImpl;
import net.sf.cglib.proxy.Enhancer;
public class CglibUnit {
public static void main(String[] args) {
CglibProxy proxy=new CglibProxy();
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(PersonImpl.class);
enhancer.setCallback(proxy);
PersonImpl per = (PersonImpl)enhancer.create();
per.SayHello();
}
}
像这样的方式就可以不要求一定需要声明接口就可以动态代理,但是不管是JDK代理或者CgLib代理,都需要事先声明PersonImpl实体类,就是说被动态创建的对象都需要声明好,假如说如果不想手动声明这样的一个实体类(被动态创建的对象),又或者说即使是声明了类似于PersonImpl这样的实体对象,但需要能够动态的为它新增一些新的属性并且赋值,这些想法都可以实现.,下面说一下该怎么做:
3.动态代理
一个动态Bean,读取属性文件内容作为被创建对象的属性,当然你也可以选择不使用属性文件,直接写在代码上也可以;
package yzr.dynamiceBean;
import java.util.Iterator;
import java.util.Map;
import java.util.Set;
import net.sf.cglib.beans.BeanGenerator;
import net.sf.cglib.beans.BeanMap;
public class DynamicBean {
private Object object = null;//动态生成的类
private BeanMap beanMap = null;//存放属性名称以及属性的类型
public DynamicBean() {
super();
}
public DynamicBean(Map propertyMap) {
this.object = generateBean(propertyMap);
this.beanMap = BeanMap.create(this.object);
}
public void setValue(Object property, Object value) {
beanMap.put(property, value);
}
public Object getValue(String property) {
return beanMap.get(property);
}
public Object getObject() {
return this.object;
}
private Object generateBean(Map 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();
}
}
package yzr.dynamiceBean;
import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Properties;
import java.util.Set;
public class ClassUtil {
public Object dynamicClass(Object object) throws Exception {
HashMap returnMap = new HashMap();
HashMap typeMap = new HashMap();
// 读取配置文件
Properties prop = new Properties();
String sourcepackage = object.getClass().getName();
String classname = sourcepackage.substring(sourcepackage
.lastIndexOf(".") + 1);
InputStream in = ClassUtil.class
.getResourceAsStream("/Dynamic.properties");
prop.load(in);
Set<String> keylist = prop.stringPropertyNames();
Class type = object.getClass();
BeanInfo beanInfo = Introspector.getBeanInfo(type);
PropertyDescriptor[] propertyDescriptors = beanInfo
.getPropertyDescriptors();
//添加自身属性
for (int i = 0; i < propertyDescriptors.length; i++) {
PropertyDescriptor descriptor = propertyDescriptors[i];
String propertyName = descriptor.getName();
if (!propertyName.equals("class")) {
Method readMethod = descriptor.getReadMethod();
Object result = readMethod.invoke(object, new Object[0]);
if (result != null) {
returnMap.put(propertyName, result);
} else {
returnMap.put(propertyName, "");
}
typeMap.put(propertyName, descriptor.getPropertyType());
}
}
// 加载配置文件中的属性
Iterator<String> iterator = keylist.iterator();
while (iterator.hasNext()) {
String key = iterator.next();
returnMap.put(key, prop.getProperty(key));
typeMap.put(key, Class.forName("java.lang.String"));
}
// map转换成实体对象
DynamicBean bean = new DynamicBean(typeMap);
// 赋值
Set keys = typeMap.keySet();
for (Iterator it = keys.iterator(); it.hasNext();) {
String key=it.next().toString();
bean.setValue(key, returnMap.get(key));
}
Object obj = bean.getObject();
return obj;
}
public static void main(String[] args) throws Exception {
Object object = new ClassUtil().dynamicClass(new Object());
Class c = object.getClass();
Method[] methods = c.getDeclaredMethods();// 得到方法
Field[] fs = c.getDeclaredFields();
for (int i = 0; i < fs.length; i++) {
Field f = fs[i];
f.setAccessible(true); // 设置些属性是可以访问的
Object val = f.get(object);// 得到此属性的值
String type = f.getType().toString();// 得到此属性的类型
System.out.println("type=" + type + "\t name:" + f.getName()
+ "\t value = " + val);
}
}
}
属性文件Dynamic.properties:
name=YZR;
运行结果:
被动态创建对象中的属性会带有$cglib_prop前缀;
案例代码下载:点击下载案例