由上文我们开始进行自行搞出个动态代理。
首先创建一个KInVocationHandler接口
/\*\*
\* 创建一个KInVocationHandler的接口
\*/
public interface KInVocationHandler {
public Object invoke(Object proxy, Method method,Object\[\] args) throws Throwable;
}
然后我们再创建一个KClassLoader,我们自己的ClassLoder
package com.kaysanshi.design\_pattern.proxy;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
// 定义一个类加载器
/\*\*
\* ClassLoader类使用委托模型搜索类和资源。每个ClassLoader实例都有一个关联的父类加载器。当请求查找类或资源时,
\* ClassLoader实例会将对类或资源的搜索委托给其父类加载器,然后再尝试查找类或资源本身。虚拟机的内置类加载器(称为“引导类加载器”)本身没有父级,
\* 但可以用作ClassLoader实例的父级
\*/
public class KClassLoader extends ClassLoader{
private File classPathFile;
public KClassLoader(){
// 获取KClassLoader类的路径
String classPath = KClassLoader.class.getResource("").getPath();
this.classPathFile=new File(classPath);
}
/\*\*
\* 查找具有指定的<a href="name">二进制名称<a>的类。该方法应由遵循用于加载类的委托模型的类加载器实现重写,
\* 并且将在检查父类加载器中的所请求类之后由{@link loadClass <tt> loadClass <tt>}方法调用
\* @param name
\* @return
\* @throws ClassNotFoundException
\*/
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
// 获取 class的name xxx.package.name
String className= KClassLoader.class.getPackage().getName()+"."+name;
if(classPathFile !=null){
// 创建文件
File classFile = new File(classPathFile,name.replaceAll("\\\\.","/")+".class");
if (classFile.exists()){
FileInputStream inputStream =null;
ByteArrayOutputStream outputStream=null;
try {
inputStream = new FileInputStream(classFile);
outputStream = new ByteArrayOutputStream();
byte \[\] buffer = new byte\[1024\];
int len;
// 读取并写入流中
while((len = inputStream.read(buffer))!=-1){
outputStream.write(buffer,0,len);
}
// 将字节数组转换为Class类的实例。在使用该类之前,必须先对其进行解析。
//此方法将默认的ProtectionDomain分配给新定义的类。
// Policy.getPolicy().getPermissions(new CodeSource(null, null))时,
// 将有效地授予ProtectionDomain相同的权限集。默认域在第一次调用defineClass创建,并在后续调用中重用
return defineClass(className,outputStream.toByteArray(),0,outputStream.size());
}catch (Exception e){
e.printStackTrace();
}finally {
if(inputStream!=null){
try {
inputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
if(outputStream!=null){
try {
outputStream.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
}
}
return null;
}
}
创建代理的生成代理代码的类:
package com.kaysanshi.design\_pattern.proxy;
import javax.tools.JavaCompiler;
import javax.tools.JavaFileObject;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
/\*\*
\* 生成源代码的工具类
\*/
public class KProxy {
public static final String ln = "\\r\\n";
public static Object newProxyInstance(KClassLoader classLoader, Class<?>\[\] interfaces, KInVocationHandler inVocationHandler) {
try {
// 动态生成源代码 .java文件
String src = generateSrc(interfaces);
// java文件输出磁盘输出成$Proxy0.java的文件
String filePath = KProxy.class.getResource("").getPath();
File file = new File(filePath + "$Proxy0.java");
FileWriter fileWriter = new FileWriter(file);
fileWriter.write(src);
fileWriter.flush();
fileWriter.close();
// 把生成的.java文件编译成.class文件
// 获取与此平台一起提供的Java™编程语言编译器。
JavaCompiler systemJavaCompiler = ToolProvider.getSystemJavaCompiler();
// 获取此工具的标准文件管理器实现的新实例。文件管理器将使用给定的诊断侦听器来生成任何非致命的诊断。致命错误将以适当的例外方式发出信号
StandardJavaFileManager standardFileManager = systemJavaCompiler.getStandardFileManager(null, null, null);
// 获取表示给定文件的文件对象。
Iterable<? extends JavaFileObject> iterable = standardFileManager.getJavaFileObjects(file);
// 使用给定的组件和参数为编译任务创建未来。如CompilationTask界面中所述,编译可能尚未完成
JavaCompiler.CompilationTask task = systemJavaCompiler.getTask(null, standardFileManager, null, null, null, iterable);
// 执行此编译任务。编译只能执行一次。随后对该方法的调用抛出IllegalStateException
task.call();
standardFileManager.close();
// 把编译后生成.class的文件加载到jvm中
Class proxyClass = classLoader.findClass("$Proxy0");
Constructor constructor = proxyClass.getConstructor(KInVocationHandler.class);
// 删除生的文件
file.delete();
// 返回字节码重组以后的新的代理对象
return constructor.newInstance(inVocationHandler);
} catch (Exception e) {
}
return null;
}
private static String generateSrc(Class<?>\[\] interfaces) {
// 线程安全
StringBuffer buffer = new StringBuffer();
// 加入头文件
buffer.append("package com.kaysanshi.design\_pattern.proxy;" + ln)
.append("import com.kaysanshi.design\_pattern.proxy.Person;" + ln)
.append("import java.lang.reflect.\*;" + ln)
.append("public class $Proxy0 implements " + interfaces\[0\].getName() + "{" + ln)
.append("KInVocationHandler inVocationHandler;" + ln)
.append("public $Proxy0(KInVocationHandler inVocationHandler) {" + ln)
.append("this.inVocationHandler = inVocationHandler;" + ln)
.append("}" + ln);
for (Method method : interfaces\[0\].getMethods()) {
// 反射的中的获取参数类型
Class<?>\[\] parameterTypes = method.getParameterTypes();
StringBuffer paramNames = new StringBuffer();
StringBuffer paramValues = new StringBuffer();
StringBuffer paramClasses = new StringBuffer();
for (int i = 0; i < parameterTypes.length; i++) {
Class clazz = parameterTypes\[i\];
String type = clazz.getName();
// 返回源代码中给定的基础类的简单名称。如果基础类是匿名的,则返回一个空字符串
String paramName = toLowerFirstCase(clazz.getSimpleName());
paramNames.append(type + " " + paramName);
paramValues.append(paramName);
paramClasses.append(clazz.getName() + ".class");
if (i > 0 && i < parameterTypes.length - 1) {
paramNames.append(",");
paramClasses.append(",");
paramValues.append(",");
}
}
// 创建方法
buffer.append(" public " + method.getReturnType().getName() + " " + method.getName() + "("
+ paramNames.toString() + ") {" + ln)
.append("try{" + ln)
.append("Method m=" + interfaces\[0\].getName() + ".class.getMethod(\\"" + method.getName() + "\\",new Class\[\]{" +
paramClasses.toString() + "});" + ln)
.append((hasReturnValue(method.getReturnType()) ? "return " : "") + getCaseCode("this.inVocationHandler.invoke(this,m,new Object\[\]{" + paramValues + "})", method.getReturnType()) + ";" + ln)
.append("}catch(Error \_ex){}")
.append("catch(Throwable e){"+ln)
.append("throw new UndeclaredThrowableException(e);"+ln)
.append("}"+ln)
.append(getReturnEmptyCode(method.getReturnType()))
.append("}");
}
buffer.append("}" + ln);
return buffer.toString();
}
private static Map<Class,Class> mappings = new HashMap<>();
static {
mappings.put(int.class,Integer.class);
}
/\*\*
\* 首字母小写
\*
\* @param simpleName
\* @return
\*/
private static String toLowerFirstCase(String simpleName) {
char\[\] chars = simpleName.toCharArray();
chars\[0\] += 32;
return String.valueOf(chars);
}
/\*\*
\* 判断是否有返回
\* @param returnType
\* @return
\*/
private static boolean hasReturnValue(Class<?> returnType) {
return returnType!=void.class;
}
/\*\*
\*
\* @param
\* @param returnType
\* @return
\*/
private static String getCaseCode(String code, Class<?> returnType) {
if(mappings.containsKey(returnType)){
return "(("+mappings.get(returnType).getName()+")"+code+")."+returnType.getSimpleName()+"Value()";
}
return code;
}
private static String getReturnEmptyCode(Class<?> returnType) {
if(mappings.containsKey(returnType)){
return "return 0;";
}else if(returnType == void.class){
return "";
}else{
return "return null;";
}
}
}
然后分别进行对进行代理的类进行创建
public interface Person {
// 每一个人都办理一些事情
void handlerBusiness();
}
/\*\*
\* user:kay三石
\* time: 21:25
\* desc:
\*\*/
public class Customer implements Person{
public void handlerBusiness(){
System.out.println("花费充值办理业务");
}
}
/\*\*
\* KBoss是移动代理点的,
\*/
public class KBoss implements KInVocationHandler{
// 被代理的对象
private Object target;
@Override
public Object invoke(Object proxy, Method method, Object\[\] args) throws Throwable {
before();
method.invoke(this.target,args);
after();
return null;
}
private void after() {
System.out.println("缴纳完毕,等待移动返回数据");
}
private void before() {
System.out.println("我是中国移动代理商现在为你缴纳花费");
System.out.println("开始缴纳");
}
public Object getInstance(Object target) throws Exception{
this.target = target;
Class<?> clazz = target.getClass();
return KProxy.newProxyInstance(new KClassLoader(),clazz.getInterfaces(),this);
}
}
/\*\*
\* user:kay三石
\* time: 21:24
\* desc:
\*\*/
public class TestProxy {
public static void main(String\[\] args) throws Exception {
Person obj = (Person) new KBoss().getInstance(new Customer());
System.out.println(obj.getClass());
obj.handlerBusiness();
}
/\*\*
\* ~output
\* 我是中国移动代理商现在为你缴纳花费
\* 开始缴纳
\* 花费充值办理业务
\* 缴纳完毕,等待移动返回数据
\*/
}
经过以上的步骤就可以可能到我们自己实现的是可以使用的。核心逻辑都有注释请耐心看,可以直接跟着写一下看看效果的。ok好了