动态代理实现日志的写入

之前在学习设计模式的时候就学习过代理模式,在DRP的学习过程中,又一次遇到了代理模式,但是这次接触到的是动态代理。做项目的时候也听同学们提到过AOP,那么动态代理和AOP是一种什么样的关系呢?

   一、代理定义

图1  代理模式类图

代理模式:给某一个对象提供一个代理,并由代理对象控制对原对象的引用。

代理模式能够协调调用者和被调用这,在一定的程度上降低了系统的耦合度,但是由于在客户端和真实主题之间增加了代理对象,因此有些类型的代理模式可能会造成请求的处理速度变慢。

   二、动态代理

动态代理是一种较为高级的代理模式,它的典型应用就是Spring AOP.

在传统的代理模式中,客户端通过Proxy调用RealSubject类的request()方法,同时还在代理类中封装了其他方法(如preRequest()和postRequest()),可以处理一些其他问题,如果按照这种方式使用代理模式,那么真实主题角色必须是事先已经存在的,并将其作为代理对象的内部成员属性。如果一个真实主题角色必须对应一个代理主题角色,这将导致系统中类的个数急剧增加,因此需要想办法减少系统中类的个数,在实现不知道真实主题角色的情况下使用代理主体角色,这就是动态代理需要解决的问题。

三、实例代码

1.主题接口

public interface UserManager {

	public void addUser(String userId, String userName);

	public void delUser(String userId);

	public void modifyUser(String userId, String userName);

	public String findUser(String userId);
}

2.真实主题

public class UserManagerImpl implements UserManager {

	public void addUser(String userId, String userName) {
		try {
			System.out.println("UserManagerImpl.addUser() userId-->>" + userId);

		}catch(Exception e) {
			e.printStackTrace();
			throw new RuntimeException();
		}
	}

	public void delUser(String userId) {
		System.out.println("UserManagerImpl.delUser() userId-->>" + userId);
	}

	public String findUser(String userId) {
		System.out.println("UserManagerImpl.findUser() userId-->>" + userId);
		return "张三";
	}

	public void modifyUser(String userId, String userName) {
		System.out.println("UserManagerImpl.modifyUser() userId-->>" + userId);
	}
}

3.动态代理

Java动态代理实现相关类位于java.lang.reflect包,主要涉及两个对象,InvocationHandler接口和Proxy类。

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class LogHandler implements InvocationHandler {

	private Object targetObject;
	//Proxy为动态代理类
	public Object newProxyInstance(Object targetObject) {
		this.targetObject = targetObject;
		return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(),
							   targetObject.getClass().getInterfaces(), this);
	}
	/*
	 * @proxy:表示代理类
	 * @method:表示需要代理的方法
	 * @args:表示代理方法的参数数组
	 */
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		System.out.println("start-->>" + method.getName());
		for (int i=0; i<args.length; i++) {
			System.out.println(args[i]);
		}
		Object ret = null;
		try {
			//调用目标方法
			ret = method.invoke(targetObject, args);
			System.out.println("success-->>" + method.getName());
		}catch(Exception e) {
			e.printStackTrace();
			System.out.println("error-->>" + method.getName());
			throw e;
		}
		return ret;
	}
}

在newProxyInstance方法中,目标主题作为参数,我们通过targetObject.getClass().getClassLoader()获取ClassLoader对象,然后通过targetObject.getClass().getInterfaces()获取它实现的所有接口,这样就在内存中建立了一个动态代理对象。但是值得注意的一点是,这个被建立的动态代理类里面只有目标主题的方法,而没有其实现,当客户端调用的动态代理类的方法时,需要调用一个实现了InvocationHandler接口的类,这样才能代用InvocationHandler中的invoke()回调方法,所以要把LogHandler自身作为参数传入。

4.客户端调用

public class Client {

	public static void main(String[] args) {
		LogHandler logHandler = new LogHandler();
		UserManager userManager = (UserManager)logHandler.newProxyInstance(new UserManagerImpl());

		String name = userManager.findUser("0001");
		System.out.println("Client.main() --- " + name);
	}
}

在这里,userManager作为代理对象,调用userManager.findUser()就会调用InvocationHandler中的invoke方法,所以在invoke()方法中处理相应的日志操作即可。

总结:

代理模式的进一步深入学习,越发感觉到面向对象编程的魅力。invoke()可以联想到在学习js的回调函数,所以接收起来并不太陌生。动态代理模式解决了静态代理模式要求创建多个代理类的缺陷,把编译时创建的实例延迟到运行时。AOP将日志记录,性能统计,安全控制,事务处理,异常处理等代码从业务逻辑代码中划分出来,通过对这些行为的分离,我们希望可以将它们独立到非指导业务逻辑的方法中,进而改变这些行为的时候不影响业务逻辑的代码。无疑,代理模式为AOP的实现提供了良好的解决思路。

时间: 2024-10-10 17:25:49

动态代理实现日志的写入的相关文章

Java 动态代理插入日志

被代理对象的接口 1 public interface IScoreService { 2 public void addScore(String s,String s1); 3 } 被代理的对象的实现 1 public class ScoreServiceImpl implements IScoreService{ 2 int score = 0; 3 public List<Integer> sList = new ArrayList<Integer>(); 4 5 publi

java开发必学知识:动态代理

目录 1. 引言 2. 代理模式及静态代理 2.1 代理模式说明 2.2 静态代理 2.3 静态代理局限性 3. 动态代理 3.1 JAVA反射机制 3.2 JDK动态代理 3.2.1 JDK动态代理 3.2.2 JDK动态代理与限制 3.4 CGLIB动态代理 4. 动态代理在Spring的应用:AOP 4.1 AOP 概念 4.2 AOP编程 4.2.1 引入aop依赖 4.2.2 定义切面.切点与通知 5. 总结 参考资料 往期文章 一句话概括:java动态代理通过反射机制,可在不修改原代

使用动态代理解决方法调用前后添加日志信息

一般情况,在每个调用的方法中直接添加日志信息,存在如下问题: 1.代码混乱:越来越多的非业务需求加入(如日志和验证等)后,原有的业务方法急剧膨胀,每个方法在处理核心逻辑的同时还必须兼顾其他多个关注点: 2.代码分散:以日志需求为例,只是为了满足这个单一的需求,就不得不在多个模块里多次重复相同的日志代码,如果日志需求发生变化,必须修改所有的模块. 针对以上问题,使用动态代理带解决. 代理设计模式的原理:使用一个代理将对象包装起来,然后用该代理取代原始对象.任何原始对象的调用都要通过代理.代理对象决

java动态代理详解,并用动态代理和注解实现日志记录功能

动态代理的概念 动态代理是程序在运行过程中自动创建一个代理对象来代替被代理的对象去执行相应的操作,例如, 我们有一个已经投入运行的项目中有一个用户DAO类UserDao用来对User对象进行数据库的增删改查操作,但是有一天,要求在对用户的增删改查操作时记录相应的日志,这是怎么办呢?难道我们去直接修改UserDao的源代码,然后在UserDao的每个方法中加入日志记录功能,这显然是不合理的,它违背了java的OCP原则,即对修改关闭对扩张开放.比如改现有的代码如下: 接口类 public inte

日志 动态代理

日志log4j.properties 框架: log4j配置文件:log4j.rootLogger=TRACE,console,f1 log4j.appender.console=org.apache.log4j.ConsoleAppenderlog4j.appender.console.layout=org.apache.log4j.PatternLayoutlog4j.appender.console.layout.ConversionPattern=[%p] %m [%t] %c [%l]

静态代理与动态代理的简单使用

代理模式(Proxy Pattern)是一种比较常见的设计模式,在很多场合都会被用到. 所谓代理指的是让其他的类代替完成一些任务(执行一些方法等),在软件开发中代理模式具有非常重要的作用,面向切面编程(AOP)便是基于代理模式运作的编程范式. 下面介绍一下其中的静态代理与动态代理,基于Java语言. 静态代理: 首先由一个HelloWorld接口,其中有一个方法,print public interface HelloWorld { void print(); } 接下来是实现了HelloWor

AOP与JAVA动态代理

1.AOP的各种实现 AOP就是面向切面编程,我们可以从以下几个层面来实现AOP 在编译期修改源代码 在运行期字节码加载前修改字节码 在运行期字节码加载后动态创建代理类的字节码 2.AOP各种实现机制的比较 以下是各种实现机制的比较: 类别 机制 原理 优点 缺点 静态AOP 静态织入 在编译期,切面直接以字节码的形式编译到目标字节码文件中 对系统无性能影响 灵活性不够 动态AOP 动态代理 在运行期,目标类加载后,为接口动态生成代理类,将切面织入到代理类中 相对于静态AOP更加灵活 切入的关注

Java动态代理简单应用

概念 代理模式是基本的设计模式之一,它是开发者为了提供额外的或不同的操作,而插入的用来代替“实际”对象的对象.这些操作通常涉及与“实际”对象的通信,因此代理通常充当着中间人的角色. Java动态代理比代理的思想更进一步,因为它可以动态地创建代理并动态地处理对代理方法的调用.在动态代理上所做的所有调用都会被重定向到单一的调用处理器(InvocationHandler)上,调用处理器的工作是揭示调用的类型并确定相应的策略. Java动态代理实现机制采用了反射的思想,有关于反射的基础知识,可以参见博客

模拟JDK动态代理类的实现

问题: 要理解动态代理及其优点,我们先从这样一个问题入手,比如现在我们有UserDao这样一个接口,里面有addUser()方法,同时有一个UserDaoImpl类实现了该接口,具体实现了addUser()方法,现在我要实现在该方法前后记录日志的功能,有什么解决办法呢? 在源代码上直接修改.第一反应肯定是直接在源码上添加该功能,但是如果我的需求变成在所有的DaoImpl包里的类的所有的方法都添加记录日志的功能,那再去每一个都添加,工作量大,代码的重用率也不高,而且有的时候你可能没有源代码,所以该