java动态代理

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前缀;

案例代码下载:点击下载案例

### Java 动态代理的实现原理与用法 #### 1. Java 动态代理概述 Java 动态代理是一种在运行时动态生成代理对象的技术,它允许开发者无需提前定义具体的代理类即可完成方法拦截和增强功能。这种机制广泛应用于 AOP(面向切面编程)、事务管理以及日志记录等领域[^2]。 #### 2. 动态代理的核心组件 动态代理主要依赖于 `java.lang.reflect.Proxy` 类和 `InvocationHandler` 接口来实现。以下是其核心组成部分: - **Proxy 类**: 提供了用于创建动态代理实例的方法。 - **InvocationHandler 接口**: 定义了一个处理方法调用的回调接口,通过该接口可以自定义代理行为。 当客户端调用代理对象上的某个方法时,实际执行的是由 InvocationHandler 处理逻辑所指定的操作[^3]。 #### 3. JDK 原生动态代理实现 JDK 动态代理基于反射技术,在运行期间为一组接口动态生成代理类及其实例。具体流程如下: - 创建一个实现了 `InvocationHandler` 接口的对象。 - 使用 `Proxy.newProxyInstance()` 方法传入目标类加载器、目标类实现的一组接口列表以及上述 handler 对象,从而获得代理实例。 下面是一个简单的示例代码展示如何利用 JDK 动态代理实现基本的日志打印功能: ```java import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; // 定义服务接口 interface GreetingService { void sayHello(String name); } // 实现服务接口的具体业务逻辑 class SimpleGreetingServiceImpl implements GreetingService { @Override public void sayHello(String name) { System.out.println("Hello, " + name); } } // 自定义 InvocationHandler 来拦截并扩展方法调用 class LoggingInvocationHandler implements InvocationHandler { private Object target; // 被代理的目标对象 public LoggingInvocationHandler(Object target) { this.target = target; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("[Before] Executing: " + method.getName()); // 执行原始方法 Object result = method.invoke(target, args); System.out.println("[After] Finished execution."); return result; } } public class JdkDynamicProxyDemo { public static void main(String[] args) { // 初始化真实的服务实现 GreetingService greetingService = new SimpleGreetingServiceImpl(); // 构建带有日志功能的代理对象 GreetingService proxyInstance = (GreetingService) Proxy.newProxyInstance( greetingService.getClass().getClassLoader(), greetingService.getClass().getInterfaces(), new LoggingInvocationHandler(greetingService)); // 测试代理效果 proxyInstance.sayHello("World"); } } ``` 此程序展示了如何通过动态代理增加额外的功能而修改原有代码结构[^1]。 #### 4. CGLib 动态代理实现 除了 JDK 内置支持外,还可以借助第三方库如 CGLib 进行动态代理操作。CGLib 主要针对那些未继承任何接口或者希望直接操控实体类场景下更为适用。它的内部工作机理涉及字节码层面操作,能够子类化任意非 final 的普通类,并重写其中的方法达到相同目的。 需要注意的是,由于两者设计初衷同,在性能表现上可能会有所差异;通常情况下,如果仅需对接口做封装,则推荐优先考虑更轻量级也更加直观易懂的 JDK 方案。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值