黑马程序员----动态代理

本文深入探讨了Java中的动态代理机制,包括其概念、工作原理及具体实现方式。介绍了如何利用JVM生成动态类来实现代理,并通过代码示例展示了动态代理在实际应用中的灵活性和强大功能。

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

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

 什么是代理:要为已存在的多个具有相同接口的目标类的方法增加一些系统功能。比如:事物处理,异常处理,日志等。
 也就是业务交叉。面向切面编程AOP(Aspect Oriented program)
  
  什么是动态代理:JVM可以再运行期间动态生成出类的字节码,这种动态生成的类往往被用作代理类,即动态代理类。
 两中实现方式:
JVM生成动态类必须实现一个或多个接口,所以jvm生成的动态类只能用作具有相同接口的目标类的代理。

怎么让一个没有实现接口的类生成动态代理类呢?可以使用CGLIB库。他可以动态的生成一个类的子类,一个类的子类也可以用作该类代理类。

动态代理工作原理图:


代码实现:分析JVM生成动态类,以及获取生成动态类的方法信息列表

package Proxy;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;

public class ProxyDemo {

	/**
	 * @分析JVM生成动态类,以及获取生成动态类的方法信息列表
	 */
	public static void main(String[] args)  throws Exception{
		
		//通过反射获取jvm生成动态的字节码文件
		//参数说明: 第一个参数classLoader:一般使用使用接口的类加载器,第二个参数:该动态类需要实现的接口
	Class clazzProxy1=	Proxy.getProxyClass(Collection.class.getClassLoader(), Collection.class);
	System.out.println(clazzProxy1.getName());
	//获取构造方法
	Constructor[] constructors=clazzProxy1.getConstructors();
	for(Constructor constructor: constructors){
		System.out.println(constructor);
		//这个打印出public $Proxy0(java.lang.reflect.InvocationHandler)  。说明只有一个构造方法。
	}
	
	System.out.println("begin new instance-------");
	Constructor constructor=clazzProxy1.getConstructor(InvocationHandler.class);
	Collection proxy1=(Collection) constructor.newInstance(new InvocationHandler() {
		
		@Override
		public Object invoke(Object proxy, Method method, Object[] args)
				throws Throwable {
			// TODO Auto-generated method stub
			return null;
		}
	});
	System.out.println(proxy1);
    //	proxy1.size(); size()方法有返回值。报空指针错误
	
	System.out.println("第二种创建动态实例对象方法:");
	Collection proxy2=(Collection) Proxy.newProxyInstance(
			Collection.class.getClassLoader(),
			new Class[]{Collection.class},
			new InvocationHandler() {
				ArrayList traget=new ArrayList();
				@Override
				public Object invoke(Object proxy, Method method, Object[] args)
						throws Throwable {
					long beginTime=System.currentTimeMillis();
	                Object retVal=method.invoke(traget, args);
	                long endTime=System.currentTimeMillis()-beginTime;
	                System.out.println(method.getName()+"耗时"+(endTime-beginTime));
					return retVal;
				}
			});
	    proxy2.add("zd");
	    proxy2.add("lx");
	    proxy2.add("wcb");
	    System.out.println(proxy2.size());
	}

}
面向切面实现,把代理类封装使用,可以插入日志信息等:
package Proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.ArrayList;
import java.util.Collection;

public class ProxyDemo2 {
	public static void main(String[] args) {
		  	Collection  traget=new ArrayList();
		Collection proxy2 = (Collection) getProxy(traget,new AdvicceService());
		    proxy2.add("zd");
		    proxy2.add("lx");
		    proxy2.add("wcb");
		    System.out.println("---------"+proxy2.size());
	}

	 /**
	  * 此方法可以一直使用,动态代理类
	  * @param traget
	  * @param advice
	  * @return proxy2
	  */
	private static Object getProxy(final Object traget,final Advice advice) {
		Object proxy2= Proxy.newProxyInstance(
				traget.getClass().getClassLoader(), //用什么接口就用它的类加载器
				traget.getClass().getInterfaces(), 
				new InvocationHandler() {
					@Override
					public Object invoke(Object proxy, Method method, Object[] args)
							throws Throwable {
					    advice.beforMethod(method); 
		                Object retVal=method.invoke(traget, args);
		                advice.afterMethod(method);
						return retVal;
					}
				});
		return proxy2;
	}

}
接口:
package Proxy;

import java.lang.reflect.Method;

public interface Advice {
	
	 void beforMethod(Method method);
	 void afterMethod(Method method);

}
接口实现类:
package Proxy;

import java.lang.reflect.Method;

public class AdvicceService implements Advice {

	private long beginTime=0;
	@Override
	public void beforMethod(Method method) {
		
		beginTime=System.currentTimeMillis();
		
	}

	@Override
	public void afterMethod(Method method) {
		  long endTime=System.currentTimeMillis()-beginTime;
          System.out.println(method.getName()+"耗时"+(endTime-beginTime));
		
	}

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




### 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、付费专栏及课程。

余额充值