黑马程序员-java动态代理

本文深入探讨了Java动态代理的核心概念和技术细节,包括AOP的基本原理、Proxy类与InvocationHandler接口的作用及其实现方式,还提供了具体的代码示例,展示了如何通过配置文件灵活地创建代理对象。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

----------------------android培训java培训、期待与您交流! ----------------------

AOP(Aspect oriented program) 面向方面的编程AOP的目标就是要使交叉业务模块化,可以采用将切面代码移动到原始方法的周围,这与直接在方法中编程切面代码的运行效果是一样的。

1.proxy类:

构造方法:

protected Proxy(InvocationHandler h)

使用其调用处理程序的指定值从子类(通常为动态代理类)构建新的Proxy实例。

方法:

static Object newProxyInstance(ClassLoaderloader,Class<?>[]interfaces, InvocationHandler h) 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。

static Class<?> getProxyClass(ClassLoaderloader,Class<?>...interfaces) 返回代理类的java.lang.Class对象,并向其提供类加载器和接口数组。

static InvocationHandler getInvocationHandler(Objectproxy)返回指定代理实例的调用处理程序。

static boolean isProxyClass(Class<?> cl) 当且仅当指定的类通过 getProxyClass方法或newProxyInstance方法动态生成为代理类时,返回true

2.InvocationHandler接口

Object invoke(Object proxy, Methodmethod,Object[]args) 在代理实例上处理方法调用并返回结果。这个方法的proxy就是InvocationHandler所属于的代理对象,method就是代理对象调用的方法,args就是代理对象调用的方法里面的参数。在invoke内部,menthod会调用invoke方法作用于目标对象身上。目标对象即target

3.创建动态代理类的方法

Collection接口的动态代理类为例

A.使用Proxy.getProxyClass(ClassLoaderloader,Class<?>...interfaces)方法来获取动态代理类的class,然后在调用这个class的构造方法Proxy(InvocationHandlerh)创建实例。【期间通过反射获取构造方法。】

Collection proxy= (Collection)Proxy.getProxyClass(Collection.class.getClassLoader,Collection.class).getConstrctor(InvocationHandler.class).newInstance(newInvocationHandler(){

public Object invoke(Object target,Methodmethod,ObjectparaListOfMethod[]){}

})

B.使用Proxy.newProxyInstance(ClassLoaderloader,Class<?>[]interfaces, InvocationHandler h) 方法来直接创建动态代理类的实例

Collection proxy= (Collection)Proxy.newProxyInstance(Collection.class.getClassLoader,Collection.class,newInvocationHandler(){

public Object invoke(Object target,Methodmethod,ObjectparaListOfMethod[]){}

})

怎样将目标类传入代理的Invoke方法中?

target和系统代码[即我们要在方法前或后面执行的代码]封装成对象,抽到InvocationHandler外面,之后通过参数的方法传递进去。getProxytarketadvice

InvocationHandler类里面只复写了Object里面的equalstoStringhashCode方法。没有复写getClass方法,所以想要获取代理类代理的目标的类名是需要自己复写getClass方法的。

代理的运作其实还是用到了反射的原理。

C. defineClass方法将一个byte数组转换为Class类的实例。这种新定义的类的实例可以使用Class.newInstance来创建

protected Class<?> defineClass(Stringname,byte[]b, int off, int len) 将一个byte数组转换为Class类的实例。

protected Class<?> defineClass(Stringname,byte[]b, int off, int len, ProtectionDomainprotectionDomain)使用可选的ProtectionDomain将一个byte数组转换为Class类的实例。

protected Class<?> defineClass(Stringname,ByteBufferb, ProtectionDomain protectionDomain) 使用可选的ProtectionDomainByteBuffer转换为Class类的实例。

D. ClassLoader

protected ClassLoader() 创建一个新的类加载器,将该加载器作为父类加载器。

protected ClassLoader(ClassLoader parent) 使用指定的、用于委托操作的父类加载器创建新的类加载器。

 

利用代理 实现一个 微型的可配置的框架;

1 配置文件通过属性名指定需要加载的类为普通类还是代理类,决定返回普通类对象或者代理对象。

这里的配置也可以通过注解来配置。

以下贴出具体代码:

package cn.itcast.enhance;

import java.io.InputStream;
import java.util.Properties;

/**
 * spring beanFactory 模拟
 * @author qinge
 *
 */
public class BeanFactory {
	
	private InputStream inputStream;
	private String adviceClassName;
	private String targetClassName;

	/**
	 * 获取资源文件中指定属性名对应的值, 并加载该值对应的字节码
	 * @param inputStream 
	 * @param targetClassName 资源文件中目标的 key
	 * @param adviceClassName 资源文件中Advice 类的 key
	 */
	public BeanFactory(InputStream inputStream,String targetClassName, String adviceClassName) {
		this.inputStream = inputStream;
		this.targetClassName = targetClassName;
		this.adviceClassName = adviceClassName;
	}



	public Object getBean(String className) throws Exception{
		Object bean = null;
		Properties properties = new Properties();
		properties.load(inputStream);
		String loadClassName = properties.getProperty(className);
		bean = Class.forName(loadClassName).newInstance();
		if(bean instanceof ProxyFactoryBean){
			ProxyFactoryBean factoryBean = (ProxyFactoryBean) bean;
			Object target = Class.forName(properties.getProperty(targetClassName)).newInstance();
			Advice advice = (Advice) Class.forName(properties.getProperty(adviceClassName)).newInstance();
			return factoryBean.getProxy(target, advice);
		}
		return bean;
		
	}

}


 

package cn.itcast.enhance;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyFactoryBean {

	/**
	 * 代理的目标对象  和 要实现系统功能的对象
	 * @param target
	 * @return
	 */
	public Object getProxy(final Object target, final Advice advice) {
		Object proxy =  Proxy.newProxyInstance(
				target.getClass().getClassLoader(),
				target.getClass().getInterfaces(),
				new InvocationHandler() {
					Object obj = null;
					@Override
					public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {
						advice.beforeMethod();
						obj = method.invoke(target, args);
						advice.afterMethod();
						return obj;
					}
				});
		return proxy;
	}
	
	

}

 

 

package cn.itcast.enhance;

import java.io.InputStream;
import java.util.List;

public class BeanFactoryFrameworkTest {
	public static void main(String[] args) throws Exception {
		InputStream inputStream = BeanFactoryFrameworkTest.class.getResourceAsStream("spring.properties");
		BeanFactory beanFactory = new BeanFactory(inputStream,"targetClassName", "adviceClassName");
		List bean = (List) beanFactory.getBean("className");
		bean.add("dd");
		System.out.println(bean.size());
		System.out.println(bean.getClass().getName());
	}

}

 

#className=java.util.ArrayList
className=cn.itcast.enhance.ProxyFactoryBean
targetClassName=java.util.ArrayList
adviceClassName=cn.itcast.enhance.MyAdvice




 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值