`

设计模式之动态代理与spring的aop编程

阅读更多

        AOP为Aspect Oriented Programming的缩写,意为:面向切面编程(也叫面向方面),可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加功能的一种技术。

动态代理是实现aop的一种主要方式。

 

动态代理的实现有JDK Compile API,CGLIB,ASM

如下是动态代理的原理

如下实例1:

接口movable

 

package com.old;
public interface Moveable {
	void move();
}

 

 实现movable接口的类Car

 

package com.old;

import java.util.Random;

public class Tank implements Moveable{

	@Override
	public void move() {
		// TODO Auto-generated method stub
		System.out.println("tank moving");
		try {
			Thread.sleep(new Random().nextInt(5000));
		} catch (InterruptedException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
}

 

此时如果要对Tank类进行扩展,比如前后记录日志,加上事务或者权限等,只有如下两种方法。

方法1:继承的方式,如Tank2.java

 

package com.old;

public class Tank2 extends Tank {
	@Override
	public void move() {
		// TODO Auto-generated method stub

		long start  = System.currentTimeMillis();
		super.move();
		long end =  System.currentTimeMillis();
		System.out.println("time: " + (end-start));
	}
}

 

 

但是如果被代理的对象较多会产生类爆炸,而且耦合性太强。

方法二:采用组合的方式,如Tank3.java

 

package com.old;

public class Tank3 implements Moveable{
	Tank tank;

	public Tank3(Tank tank) {
		super();
		this.tank = tank;
	}
	
	@Override
	public void move(){
		System.out.println("log start");
		tank.move();
		System.out.println("log end");
	}
}

 

组合的方法虽然不会产生类爆炸,但是不方便实现更多的扩展。

解决方法是采用动态代理

核心类Proxy.java

 

package com.proxy;

import java.io.File;
import java.io.FileWriter;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.net.URL;
import java.net.URLClassLoader;

import javax.tools.JavaCompiler;
import javax.tools.StandardJavaFileManager;
import javax.tools.ToolProvider;
import javax.tools.JavaCompiler.CompilationTask;

public class Proxy {
	public static Object newProxyInstance(Class intf,InvocationHandler h) throws Exception{ //JDK Compile API,CGLIB,ASM
		String rt = "\r\n";
		String methodStr = "";

		Method[] methods = intf.getMethods();
		for(Method m:methods){
			methodStr += "@Override" + rt +
						 "public void " + m.getName() + "() {" + rt +
						 " try{" + rt +
						 " Method md = " + intf.getName() + ".class.getMethod(\"" + m.getName() + "\");" + rt +
						 "h.invoke(md);" + rt +
						 "}catch(Exception e){e.printStackTrace();}" + rt +
						 "}";
			
						
		}
		
		String src = "package com.proxy;" + r
				+ "import java.lang.reflect.Method;"
				+ "import com.proxy.InvocationHandler;"
				+ "public class AbProxy implements "+ intf.getName() + "{" + rt
				+ "com.proxy.InvocationHandler h;" + rt 
				+ "public AbProxy(InvocationHandler h) {" + rt
				+ "super();"  + rt
				+ "this.h = h;" + "}" + rt

				+ methodStr + rt
				
				+ "}" ;

//		String fileName = System.getProperty("user.dir")+"/src/com/proxy/TankTimeProxy.java";

		String fileName = "E:/leanspace/temp/src/com/proxy/AbProxy.java";
		File f = new File(fileName);
		FileWriter fw = new FileWriter(f);
		fw.write(src);
		fw.close();
		//compiler
		JavaCompiler compiler = ToolProvider.getSystemJavaCompiler();
		StandardJavaFileManager fileMgr = compiler.getStandardFileManager(null, null, null);
		Iterable units =  fileMgr.getJavaFileObjects(f);
		CompilationTask t = compiler.getTask(null, fileMgr, null, null, null, units);
		t.call();
		
		//load into memory and create an instance
		URL[] url = new URL[]{new URL("file:/"+"E:/leanspace/temp/src/")};
		URLClassLoader ul = new URLClassLoader(url);
		Class c = ul.loadClass("com.proxy.AbProxy");
		
		Constructor ctr = c.getConstructor(InvocationHandler.class);
		Object m =  ctr.newInstance(h);

	
		return m;
	}
}

 

 通过java反射的机制动态的编译代理类的代码,只需要将被代理类实现的接口及对应的扩展功能处理逻辑的handler作为参数传入即可。

处理类接口:InvocationHandler.java

 

package com.proxy;

import java.lang.reflect.Method;

public interface InvocationHandler {
	public void invoke(Method m);
}	

记录时间的处理类TimeHandler.java

 

package com.proxy;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

public class TimeHandler implements InvocationHandler{
	private Object target;

	public TimeHandler(Object target) {
		super();
		this.target = target;
	}

	@Override
	public void invoke(Method m) {
		// TODO Auto-generated method stub

		long start  = System.currentTimeMillis();
		System.out.println("startTime:" + start);
		try {
			m.invoke(target, new Object[]{});
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		long end =  System.currentTimeMillis();
		System.out.println("time: " + (end-start));
		
	}

	public Object getTarget() {
		return target;
	}

	public void setTarget(Object target) {
		this.target = target;
	}

}

 

 Client.java

 

package com.proxy;

public class Client {
	public static void main(String args[]) throws Exception{
		Tank t = new Tank();
		InvocationHandler h = new TimeHandler(t);
		
		Moveable m = (Moveable)Proxy.newProxyInstance(Moveable.class,h);
	
		m.move();
	}
}

通过Proxy.newProxyInstance(Moveable.class,h)方法动态编译生成代理类,开发人员不需要关注内部实现逻辑就可以对任意实现接口的生成代理,如果要对多个功能扩展只需要这样写。

 

Tank t = new Tank();
InvocationHandler th = new TimeHandler(t);
InvocationHandler lh = new LogHandler(th);

即可很方便的扩展。当然在spring中对一些没有实现接口的类也可以产生代理类,通过二进制码的方式(cglib包)。、

 

       当每个新的软件设计师都被要求掌握如何将需求功能转化成一个个类,并且定义它们的数据成员行为,以及它们之间复杂的关系的时候,面向切面编程(Aspect-Oriented Programming,AOP)为我们带来了新的想法、新的思想、新的模式。

 

 ---

理解补充:代理类所做的事就是将被代理类。如上面的例子tank对象.move(),重写成了,move方法.invoke(tank对象)的方式,通过handle类进行一层的invoke方法的包装,即如下代码所示,去记录时间等在不改写源代码的同时进行扩展。

       @Override
	public void invoke(Method m) {
		// TODO Auto-generated method stub

		long start  = System.currentTimeMillis();
		System.out.println("startTime:" + start);
		try {
			m.invoke(target, new Object[]{});
		} catch (Exception e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} 
		long end =  System.currentTimeMillis();
		System.out.println("time: " + (end-start));
		
	}

 

分享到:
评论

相关推荐

    spring之AOP(动态代理)

    在Spring框架中,AOP(面向切面编程)是一种强大的设计模式,它允许开发者将关注点分离,将横切关注点(如日志、事务管理、权限检查等)与核心业务逻辑解耦。AOP的核心概念是切面、通知、连接点、切入点和织入。在...

    使用动态代理演示Spring的AOP编程原理

    为了说明Spring的AOP原理,本人使用代理模式中的动态代理完成演示AOP编程的原理的演示。相信,如果你耐心看完整个程序(几乎一行注释一行代码),那么你对Spring这个东西就不是觉得有什么神秘了! 阅读对象:凡是喜爱...

    通过动态代理模拟Spring AOP

    在Java编程领域,AOP(Aspect Oriented Programming,面向切面编程)是一种强大的设计模式,它允许程序员将关注点从核心业务逻辑中分离出来,比如日志、事务管理、性能监控等。Spring框架中的AOP模块是实现这一模式...

    代理模式,JDK动态代理,SpringAOP来龙去脉

    代理模式是一种设计模式,它允许我们为一个对象创建一个代理对象,这个代理对象在客户端与目标对象之间起到中介的作用,可以增强或修改目标对象的行为,同时保持相同的接口。在Java中,我们可以使用JDK的动态代理...

    反射实现 AOP 动态代理模式(Spring AOP 的实现 原理) - Java 例子 -

    在Java编程中,AOP(面向切面编程)是一种强大的设计模式,它允许开发者将关注点分离,将横切关注点(如日志、事务管理)与核心业务逻辑解耦。Spring框架是Java中实现AOP的一个流行工具,它通过动态代理机制实现了这...

    第四章:Spring AOP API 设计模式1

    【Spring AOP设计模式】是Spring框架中面向切面编程的重要组成部分,它允许开发者通过分离关注点来解耦代码,实现灵活的模块化设计。在本章中,我们将探讨17种设计模式在Spring AOP中的应用和实现,以及它们如何帮助...

    代理设计模式:静态代理和动态代理的理解、实现与区别(优缺点)与SpringAOP的3种配置方式案例工程代码

    代理设计模式是软件开发中的一种重要模式,它允许我们在不修改原有对象的基础上,通过代理对象对原对象进行增强或控制。本资源主要涵盖了静态...通过学习和实践,你可以更好地掌握代理设计模式以及Spring AOP的使用。

    java中动态代理,springAop.pdf

    Java中的动态代理是一种强大的设计模式,它允许在运行时创建具有特定行为的代理类,这些代理类可以扩展或修改原始类的功能。Spring AOP(面向切面编程)是Spring框架的一部分,它使用动态代理实现切面逻辑,如日志、...

    Spring AOP编程实例

    **Spring AOP编程实例** Spring AOP(Aspect Oriented Programming,面向切面编程)是Spring框架的核心特性之一,它提供了一种在不修改原有代码的情况下,通过插入额外的行为(如日志、事务管理等)来增强功能的...

    spring使用动态代理面向切面编程(AOP) xml

    在Spring框架中,面向切面编程(AOP)是一种强大的设计模式,它允许开发者将关注点分离,将横切关注点(如日志、事务管理、权限检查等)与核心业务逻辑解耦。本篇文章将深入探讨如何使用Spring的动态代理机制实现AOP...

    代理模式(含动态代理讲解)【Spring AOP实质】

    代理模式是一种设计模式,它允许我们为一个对象创建一个代理对象,这个代理对象在客户端和目标对象之间起到中介的作用,可以增强或控制对目标对象的访问。代理模式在实际开发中有着广泛的应用,特别是在需要进行额外...

    模拟spring aop【一】基于jdk动态代理实现的aop

    在Spring框架中,AOP(面向切面编程)是一种强大的设计模式,它允许开发者定义“切面”,这些切面可以包含业务逻辑的某一部分,比如日志、事务管理或安全控制。切面可以在多个对象中统一地应用,提高了代码的复用性...

    spring aop 学习笔记

    - Spring AOP的实现涉及到反射、动态代理、代理模式等多个核心Java技术。 - `org.springframework.aop.framework.ProxyFactoryBean` 和 `org.springframework.aop.framework.JdkDynamicAopProxy` 是动态代理的关键...

    20190606_SpringAOP编程实现_田超凡.docx

    在本文档中,作者田超凡探讨了Spring AOP(面向切面编程)的实现,主要涉及了两种代理模式:静态代理和JDK动态代理。这两种代理方式都是为了实现AOP的核心理念,即在不修改原有业务代码的情况下,对代码进行横切关注...

    springioc和spring aop

    Spring框架是Java开发中不可或缺的一部分,它通过提供两种核心特性——控制反转(IoC)和面向切面编程(AOP)来简化应用的构建。理解并掌握这两种技术对于任何Java开发者来说都至关重要。 **控制反转(IoC)**,也...

Global site tag (gtag.js) - Google Analytics