java反射的典型应用----动态代理的实现

什么是动态代理(dynamic proxy)

1)代理的是接口(Interfaces),不是类(Class)。也叫基于接口的jdk动态代理。
2)利用Java的反射技术,在运行时创建一个实现某些给定接口的新类,该类也叫代理类。
3)利用Java的Proxy类,调用Proxy.newProxyInstance(),创建动态对象。
4)给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用

代理对象要明确一下几个概念

动态代理要明确 目标对象是谁 我要为谁生产代理对象 如何获取代理对象 代理对象能做什么

为什么要使用代理

在不改变目标对象方法的情况下对方法进行增强,。例如我们希望对方法的调用增加日志记录,或者对方法的调用进行拦截。(Aop)

代码解释

需求:实现一个计算器的功能,目的是想要在某个方法执行之前都加上日志输出,如果每个方法上都加上一句日志输出也可实现记录日志的功能。但是这种方法会造成代码冗余,并且后期修改和维护很不方便。通过以上的不好之处,也是我们作为开发人员必须要避免的事情。接下来我将通过jdk的动态代理方式来实现日志的输出功能。

目录结构

在这里插入图片描述
接口

package com.ghl.service;

public interface ArithmeticCalculator {
	//计算器实现连两个位数相加
	public int add( int i,int j);

}

接口实现类

package com.ghl.service.impl;

import com.ghl.service.ArithmeticCalculator;

/**
 * 被代理类
 */
public class ArithmeticCalculatorImpl  implements ArithmeticCalculator{

	@Override
	public int add(int i, int j) {
	int result=i+j;
		return result;
	}

}

代理类

package com.ghl.proxy;
import java.lang.reflect.Array;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Arrays;
import com.ghl.service.ArithmeticCalculator;
import com.ghl.service.impl.ArithmeticCalculatorImpl;

/**代理类
 *生成代理对象
 *使用jdk的动态代理
 *
 *
 *Proxy类:所有动态代理类的父类  专门用来生成动态代理类或代理对象
 *两个方法:
 *getProxyClass(ClassLoader,Class<>... interfaces);
 * 用于生成代理类Class   代理类通过类加载器生产Class对象
 
 *newInstanceProxy(loader,interfaces,invocationHandler)(常用此方法)
 *用于生成代理对象
 *
 *invocationHandler接口(很重要)
 *用来完成动态代理的整个过程  需要动态代理做什么事都要写在这里
 * 
 *
 */
public class ArithmeticCalculatorProxy {
/*
 * 动态代理要明确  目标对象是谁 我要为谁生产代理对象    如何获取代理对象    代理对象要做什么
 */
	//1.目标对象
	private ArithmeticCalculator target;  	
	//显示生成代理类的构造方法:当前代理类为那个目标类做代理的意思  创建代理类对象的同时在指定目标i类对象
	public ArithmeticCalculatorProxy(ArithmeticCalculator target) {
		this.target=target;
	}
	
//2.获得代理对象  以方法的形式生成代理对象
	public Object getProxy() {
		Object proxy;
		/*
		 * loader:类加载器 ClassLoader对象 帮助我们加载动态生成代理类
		 * interfaces:接口们  jdk基于接口的动态代理   提供目标对象的所有接口  其实就是代理类要查看你的目标类接口都有那些方法  代理类也实现这个接口  代理类和目标类就有相同的方法
		 * 代理类有目标类的方法只是一个假象  最后还是要通过我目标类来调用我具体的方法
		 * invocationHandler:完成动态代理的全部过程
		 */
		ClassLoader loader=target.getClass().getClassLoader();//使用目标对象的类加载器   
		Class[] interfaces=target.getClass().getInterfaces();//目的是让代理对象保证与目标对象都拥有相同的方法
		proxy=Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() {
			
			/*
			 * invoke:代理对象调用代理方法  会回来调用invoke方法
			 * 
			 * proxy:生成的代理对象 也就是porxy  	在invoke方法中一般不用   
			 * 
			 * method:正在被调用的一个方法对象
			 * 
			 * args:正在被调用的方法的参数
			 */
			public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//真正的动态代理从invoke方法开始
				//  记录日志
				String methodName = method.getName();
				System.out.println("LoggingProxy====》The method"+methodName+Arrays.asList(args));
				//将方法的调用返回到目标对象上
				Object result = method.invoke(target, args); //目标对象执行目标方法   相当于执行ArithmeticCalculatorImpl中的方法	
				//记录日志
				System.out.println("日志输出结束,方法调用结束");
				return result;
			}
		});
		return proxy;
	}
}

测试

package com.ghl.proxy;

import com.ghl.service.ArithmeticCalculator;
import com.ghl.service.impl.ArithmeticCalculatorImpl;

/**
 *  测试动态代理类
 */
public class Main {
	public static void main(String[] args) {
		// 保存生成的代理类的字节码文件 动态代理在内存中进行 
		System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");

		//1.创建目标类对象
		ArithmeticCalculator target = new ArithmeticCalculatorImpl();
		// 2 通过目标类对象获得代理类对象
		Object obj = new ArithmeticCalculatorProxy(target).getProxy();
		// 3.转化回具体的类型 必须是接口 因为目标类继承了接口 代理类也继承了接口 代理类和目标泪时兄弟关系
		ArithmeticCalculator proxy = (ArithmeticCalculator) obj;
		System.out.println(proxy.getClass().getName());
		int result = proxy.add(1, 1);
		System.out.println("result" + result);

	}

}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值