黑马程序员 动态代理

---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------

动态代理技术其实并不复杂,它是一个面向方面的程序设计,简单点说,就是不是针对一种特定的方法而设计。比如很多系统中都要记录安全信息、事物信息、生成日志,我们不可能一个方法一个方法的往上加代码吧,那样累赘而麻烦。这就需要用到一个类代理需要的类,然后再代理类中使用我们需要的方法,只要加上了代理类,再调用其中的所有方法都是调用我们代理类上自己定义的方法,这样就实现了面向方面程序设计。


AOP(Object Oriented Programming):

在实际的网络中,我们也很少直接使用需要客服端的信息,中间都需要加载一个代理,这样方便与操作。



代理类的建立:

既然是代理一个类,那么我们肯定无法确定需要代理的是什么类,而又要用到那个类中的方法,这肯定是使用了反射。

代理类的建立,必须得到与需要使用类有关联的代理类的Class文件对象。

通过Proxy.getProxyClass(ClassLoader loader, Class<?>... interfaces);

它必须要接收一个类加载器,和要实现代理接口的Class对象。


既然要使用Proxy这个类,就必须查看其中的构造方法、函数方法。

既然能得到Proxy的Class对象,不妨用反射列出其中的方法,可用如下方法做:

System.out.println("-------------------Proxy Method-----------------------------");
		//通过反射返回类中方法数组
		Method[] methods = clazzProxy.getMethods();
		for(Method method: methods){
			String name = method.getName();
			StringBuilder sb = new StringBuilder(name);
			sb.append("(");
			//得到每个方法的参数,通过 getParameterTypes() 方法
			Class[] clazzParams = method.getParameterTypes();
			//将参数加入一个StringBuilder,并按照格式打印
			for(Class clazzParam: clazzParams){
				sb.append(clazzParam.getName()).append(",");
			}
			if(clazzParams.length!=0)
				sb.deleteCharAt(sb.lastIndexOf(","));
			sb.append(")");
			System.out.println(sb.toString());
		}
同理得到构造方法,打印结构发现Proxy只有一个构造方法
com.sun.proxy.$Proxy0(java.lang.reflect.InvocationHandler)
其中的方法有:
-------------------Proxy Method-----------------------------
hashCode()
equals(java.lang.Object)
toString()
add(java.lang.Object)
contains(java.lang.Object)
isEmpty()
size()
toArray()
toArray([Ljava.lang.Object;)
addAll(java.util.Collection)
iterator()
remove(java.lang.Object)
clear()
containsAll(java.util.Collection)
removeAll(java.util.Collection)
retainAll(java.util.Collection)
isProxyClass(java.lang.Class)
getProxyClass(java.lang.ClassLoader,[Ljava.lang.Class;)
newProxyInstance(java.lang.ClassLoader,[Ljava.lang.Class;,java.lang.reflect.InvocationHandler)
getInvocationHandler(java.lang.Object)
getClass()
notify()
notifyAll()
wait(long)
wait(long,int)
wait()
大多都是Object类中方法,其中的newProxyInstance建立实例的方法也与InvocationHandler有关,可以推测动态代理主要是通过此方法来实现的。


查看API文档可知,newProxyInstance()返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。就是说创建出了这个代理,就能完全实现原有接口中的所有功能。那么既然这个是个代理类,当然也可以自己添加新的功能进去,这便是动态代理了,只要我们需要,完全可以加载自己想要方法进去。

下面是一个用动态代理植入广告的程序,我们也可以随意更换其中的广告内容:

这是一个sayHello的接口:

package cn.itcast.day3;

public interface SayHello {
	void sayHello();
}
此类实现了sayHello接口,也是我们需要代理的类,在其收尾植入广告:
package cn.itcast.day3;

public class TestSayHello implements SayHello {
	public void sayHello() {
		System.out.println("Hello sky!");
	}
}
创建一个代理对象,并加入植入语句:
package cn.itcast.day3;

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

public class ProxyTest {

	public static void main(String[] args) throws Exception{
		
		Class clazzProxy = Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
		//将接口定义成目标类
		final TestSayHello target = new TestSayHello();
		// 抽取出获取代理的方法,并调用之
		SayHello proxy2 = (SayHello)getProxy(target, new Test());  
		proxy2.sayHello();
	}

	private static Object getProxy(final Object target, final Test test) {
		//newProxyInstance接收3个参数 ClassLoader, Interfaces, InvocationHandler
		Object proxy2 = Proxy.newProxyInstance(target.getClass().getClassLoader(),
													  target.getClass().getInterfaces(),
													  //实现InvocationHandler中的inovke方法
													  new InvocationHandler() {
			//invoke接收的3个参数实际上就是需要代理类中对象、方法、参数
			public Object invoke(Object proxy, Method method, Object[] args)
					throws Throwable {			
				test.beforeMethod();			//调用方法前加入的植入	
				Object obj = method.invoke(target,args);
				test.behindMethod(method);  //调用方法前加入的植入
				return obj;
			}
		});
		return proxy2;
	}	
}
最后写需要植入的内容:
package cn.itcast.day3;

import java.lang.reflect.Method;

public class Test {
	long startTime = 0;
	
	public void beforeMethod(){
		System.out.println("我是插入的广告");
		startTime = System.currentTimeMillis();
	}
	
	//返回调用此方法使用的时间
	public void behindMethod(Method method){
		long endTime = System.currentTimeMillis();
		System.out.println(method.getName()+":runtime--"+(endTime-startTime));
	}
}
打印结果:
我是插入的广告
Hello sky!
sayHello:runtime--0
成功植入广告,并打印出时间,知道这个动态代理的原理后,以后再使用相同的方法时候就简单的多,并且之后的框架如ssh都是基于动态代理产生的,有助于我们理解框架的构建。











---------------------- ASP.Net+Android+IOS开发.Net培训、期待与您交流! ----------------------
### JavaEE 黑马程序员 学习资料 教程 下载 JavaEE 是企业级应用开发的重要技术栈,而黑马程序员提供了丰富的学习资源和教程,帮助开发者掌握 JavaEE 的核心技术和框架。以下是关于 JavaEE 黑马程序员学习资料的相关信息: #### 1. 黑马程序员官方课程资源 黑马程序员的 JavaEE 课程通常包括以下内容: - **基础部分**:涵盖 Java 基础、面向对象编程、集合框架等内容[^1]。 - **核心框架**:Spring 框架的学习,包括 Spring AOP、Spring MVC 等模块[^2]。 - **Web 开发**:涉及 Servlet、JSP、Filter 等 Web 技术[^3]。 - **数据库操作**:MyBatis、Hibernate 等 ORM 框架的使用。 - **分布式与微服务**:Dubbo、Spring Cloud 等微服务框架的学习。 这些课程资源通常可以通过黑马程序员的官方网站或其合作平台(如 Bilibili、优快云)获取。 #### 2. JDK 动态代理与 Spring AOP 在 JavaEE 开发中,Spring AOP 是一个重要的知识点。它默认使用 JDK 动态代理来实现代理功能。通过 `java.lang.reflect.Proxy` 类,可以调用 `newProxyInstance()` 方法创建代理对象[^2]。这种代理机制的优点在于可以在不修改原始代码的情况下增强某些方法的功能,实现无侵入式的代码扩展。 #### 3. SpringMVC 请求映射 SpringMVC 是 JavaEE 开发中的一个重要框架,用于处理 HTTP 请求和响应。通过 `@Controller` 和 `@RequestMapping` 注解,可以定义请求的映射路径[^3]。例如,以下代码展示了如何设置请求映射路径: ```java @Controller @RequestMapping("/user") // 类请求映射的路径 public class UserController { @RequestMapping("/commonParam") // 方法请求映射的路径 @ResponseBody public String commonParam(String name, int age) { System.out.println("name参数传递:" + name); System.out.println("age参数传递:" + age); return "success"; } } ``` #### 4. 学习资源下载 如果需要下载 JavaEE 相关的黑马程序员学习资料,可以尝试以下途径: - **官方网站**:访问黑马程序员官网,注册账号后可以下载相关课程资料。 - **第三方平台**:如 Bilibili、优快云、GitHub 等,搜索关键词“黑马程序员 JavaEE”可能找到免费或付费的课程资源。 - **论坛与社区**:加入 Java 开发者论坛或 QQ 群,与其他开发者交流并获取学习资料。 #### 5. 注意事项 在下载和使用学习资料时,请确保遵守版权法规。如果选择购买正版课程,可以获得更系统的学习体验和技术支持。 --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值