深入理解Spring源码分析前缀 设计模式之动态代理

    Spring AOP拦截功能主要是由JAVA动态代理实现,java中提供两种方式实现动态代理,一种基于jdk proxy代理类实现,第二种基于cglib字节码实现。jdk动态代理是由java内部的反射机制来实现的,cglib动态代理底层则是借助asm来实现。总的来说,反射机制在生成类的过程中比较高效,而asm在生成类之后的相关执行过程中比较高效。

    1、jdk代理类实现方式

第一步:代理工厂(模拟生成一个拥有对象相同的属性和方法的代理类$proxy0)

public class DDProxy{
    public static Object newProxyInstance(DDClassLoader classLoader,Class<?>[] interfaces,DDInvocationHandler h) throws IllegalArgumentException{
		//step 1:生成java文件
    	String javaSource = generaSrc(interfaces);
    	//step 2:java文件写入磁盘
    	String javaPath = classLoader.getClass().getResource("").getPath();
    	File file= null;
    	FileWriter writer = null;
    	try {
    		file = new File(javaPath+"$Proxy0.java");
			writer = new FileWriter(file);
			writer.write(javaSource);
			
		} catch (IOException e) {
			e.printStackTrace();
		}finally {
			if(writer!=null){
				try {
					writer.flush();
					writer.close();
				} catch (IOException e) {
					e.printStackTrace();
				}
				
			}
		}
    	
    	//step 3:编译生成class文件
    	JavaCompiler compliler = ToolProvider.getSystemJavaCompiler();
    	StandardJavaFileManager manager = compliler.getStandardFileManager(null, null, null);
    	Iterable iterable = manager.getJavaFileObjects(file);
    	CompilationTask task = compliler.getTask(null, manager, null, null, null, iterable);
    	task.call();
    	try {
			manager.close();
		} catch (IOException e) {
			e.printStackTrace();
		}
    	//step 4:加载class文件
    	try {
			Class cls = classLoader.findClass("$Proxy0");
			Constructor<DDInvocationHandler> constructor = cls.getConstructor(DDInvocationHandler.class);
			return constructor.newInstance(h);
		} catch (Exception e) {
			e.printStackTrace();
		} 
    	//step 5:删除生成的java和class临时文件
    	//TODO
    	return null;
    }
    /**
     * 生成java源代码
     * @param interfaces
     * @param methodes
     */
    public static String generaSrc(Class<?>[] interfaces){
    	StringBuffer stringBuffer = new StringBuffer();
    	stringBuffer.append("package "+DDProxy.class.getPackage().getName()+";");
    	stringBuffer.append("import  "+DDInvocationHandler.class.getName()+";");
    	stringBuffer.append("import java.lang.reflect.UndeclaredThrowableException;");
    	stringBuffer.append("import java.lang.reflect.Method;");
    	stringBuffer.append("public class $Proxy0 implements "+interfaces[0].getName()+"{");
    	
    	stringBuffer.append("private "+DDInvocationHandler.class.getName()+" handler;");
    	stringBuffer.append("public $Proxy0("+DDInvocationHandler.class.getName()+" handler)"+"{");
    	stringBuffer.append("this.handler=handler;");
    	stringBuffer.append("}");
    	for(Method method:interfaces[0].getMethods()){
    		stringBuffer.append("public "+method.getReturnType().getName()+ " "+ method.getName()+"(){" );
    		stringBuffer.append("try{");
    		stringBuffer.append("Method method="+interfaces[0].getName()+".class.getMethod(\""+method.getName()+"\",new Class[]{});");
    		stringBuffer.append("this.handler.invoke(this,method,"+"null"+");");
    		stringBuffer.append("} catch (RuntimeException | Error var2){");
    		stringBuffer.append("   throw var2;");
    		stringBuffer.append("} catch (Throwable var3) {");
    		stringBuffer.append("throw new UndeclaredThrowableException(var3);");
    		stringBuffer.append("}");
    		
    		stringBuffer.append("}");
    	}
    	stringBuffer.append("}");
    	return stringBuffer.toString();
    }
    public static void main(String[] args) {
		System.out.println(DDProxy.class.getResource("").getPath());
	}
}

第二步:类加载器

/**
 * 类加载器
 * @author liguorui
 */
public class DDClassLoader extends ClassLoader {
	private File file;
	public DDClassLoader() {
		String classPath = DDClassLoader.class.getResource("").getPath();
		file = new File(classPath);
	}
	@Override
	protected Class<?> findClass(String name) throws ClassNotFoundException {
		String className = DDClassLoader.class.getPackage().getName()+"."+name;
		if(file!=null){
			file = new File(file, name.replaceAll("\\.", "/")+".class");
			if(file.exists()){
				FileInputStream input = null;
				ByteArrayOutputStream out = null;
				try {
					input = new FileInputStream(file);
					out = new ByteArrayOutputStream();
					int len=-1;
					byte[] bytes = new byte[1024];
					while ((len=input.read(bytes))!=-1) {
						out.write(bytes, 0, len);
					}
					Class<?> cls = defineClass(className, out.toByteArray(), 0, out.toByteArray().length);
					return cls;
				} catch (IOException e) {
					e.printStackTrace();
				}finally {
					try {
						input.close();
						out.flush();
						out.close();
					} catch (IOException e) {
						e.printStackTrace();
					}
				}
				
			}
		}
		return null;
	}
}

第三步:InvocationHandler主要实现代理对象与目标对象的转换

public class DDIntercept implements DDInvocationHandler{
	private Object target;
	public Object getInstance(Class<?> cls){
		try {
			this.target = cls.newInstance();
			Object object = DDProxy.newProxyInstance(new DDClassLoader(), target.getClass().getInterfaces(),this);
			return object;
		} catch (InstantiationException e) {
			e.printStackTrace();
		} catch (IllegalAccessException e) {
			e.printStackTrace();
		}
		return null;
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("\n--------begin+"+method.getName()+"-----------");
		method.invoke(target, args);
		System.out.println("--------end+"+method.getName()+"-----------\n");
		return null;
	}
}

public class DDBoss {
	public static void main(String[] args) {
		Object object = new DDIntercept().getInstance(Employer.class);
		
		((Person)object).start();
		((Person)object).working();
		((Person)object).stop();
	}
}
运行效果:

--------begin+start-----------
开始工作
--------end+start-----------

--------begin+working-----------
工作中
--------end+working-----------

--------begin+stop-----------
结束工作
--------end+stop-----------

2、CGLib代理类

    CGlib是一个优秀的动态代理框架,它的底层会使用ASM在内存中产生被代理类的子类,使用CGLib过程中被代理类不用实现任何接口。CGLIB使用简单,运行速度要远快于JDK的Proxy动态代理


//拦截类,它是Callback接口的子接口,需要用户实现
public class CGLibIntercept implements MethodInterceptor{
	public Object getInstance(Class<?> cls){
		Enhancer enhancer = new Enhancer();//主要的增强类
        enhancer.setSuperclass(cls);//设置父类,被增强的类 
        enhancer.setCallback(this);//回调对象  
        return enhancer.create();//用cglibProxy来增强被代理对象
	}
	@Override
	public Object intercept(Object obj, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
		System.out.println("\n--------begin+"+method.getName()+"-----------");
		methodProxy.invokeSuper(obj, objects);
		System.out.println("--------end+"+method.getName()+"-----------\n");
		return null;
	}
}

public class CGLibBoss {
	public static void main(String[] args) {
		Person person = (Person)new CGLibIntercept().getInstance(Employer.class);
		person.start();
		person.working();
		person.stop();
	}
}

运行效果:
--------begin+start-----------
开始工作
--------end+start-----------

--------begin+working-----------
工作中
--------end+working-----------

--------begin+stop-----------
结束工作
--------end+stop-----------

    原文作者:Spring MVC
    原文地址: https://blog.csdn.net/liguoruiq/article/details/79702307
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞