Spring静态代理和动态代理代码详解

 更新时间:2017年11月27日 10:37:54   作者:zhouyeqin  
这篇文章主要介绍了Spring静态代理和动态代理代码详解,具有一定参考价值,需要的朋友可以了解下。

本节要点:

Java静态代理
Jdk动态代理

1 面向对象设计思想遇到的问题

在传统OOP编程里以对象为核心,并通过对象之间的协作来形成一个完整的软件功能,由于对象可以继承,因此我们可以把具有相同功能或相同特征的属性抽象到一个层次分明的类结构体系中。随着软件规范的不断扩大,专业化分工越来越系列,以及OOP应用实践的不断增多,随之也暴露了一些OOP无法很好解决的问题。

现在假设系统中有三段完全相似的代码,这些代码通常会采用“复制”、“粘贴”方式来完成,通过这种方式开发出来的软件如图所示:

可能读者已经发现了这种做法的不足之处,如果有一天,蓝色背景的代码需要修改,那是不是要同时修改三个地方?如果不仅仅是这三个地方包含这段代码,而是100个,甚至是1000个地方,那会是什么后果?

记录日志在代码中无处不在---先来看一个例子:

为了跟踪应用程序的运行过程,很多方法都需要记录日志信息。我们一般这样写:

//log4j的使用见文章“log4j介绍”
import org.apache.log4j.Logger;
public class Person {
	private Logger logger = Logger.getLogger(Person.class);
	public void sleep(){
		logger.info(“开始执行时间:“ + new Date());
		System.out.println("睡觉中");
		logger.info(“执行结束时间:” + new Date());
	}
	public void eating(){
		logger.info("开始执行时间:“ + new Date()");
		System.out.println("正在吃饭中");
		logger.info("“执行结束时间:” + new Date()");
	}
}

提问:弊端在哪里?

l混淆了业务方法本身的职责

l维护工作量巨大

2解决方案1

静态代理:
   1、需要知道核心类(被代理类)是哪一个类,并且有什么方法。 
   2、非核心的代码需要重复写多次,显得代码的结构臃肿,形成代码冗余。
   3、非核心类(代理类)需要实现核心类(被代理类)实现的接口,也就是他们需要实现共同的接口,但是以核心类实现的接口(被代理类)为准。

l目地是将业务代码与日志代码完全分离,实现松散耦合.

l代理对象与被代理对象必须实现同一接口,在代理对象中实现与日志记录的相关服务,并在需要的时候呼叫被代理对象,而被代理对象只保留业务代码.

静态代理的实现

1)定义接口:

public interface IPerson {
	public abstract void sleep();
	public abstract void eating();
}

2) 被代理类

public class Person implements IPerson {
	public void sleep(){
		System.out.println("睡觉中");
	}
	public void eating(){
		System.out.println("正在吃饭中");
	}
}

3) 代理类

import org.apache.log4j.Logger;
public class PersonProxy implements IPerson {
	private IPerson person;
	private Logger logger = Logger.getLogger(PersonProxy.class);
	public PersonProxy(IPerson person) {
		this.person = person;
	}
	public void eating() {
		logger.info("开始执行时间:“ + new Date()");
		person.eating();
		logger.info("“执行结束时间:” + new Date()");
	}
	public void sleep() {
		logger.info("开始执行时间:“ + new Date()");
		person.sleep();
		logger.info("“执行结束时间:” + new Date()");
	}
}

4) 测试类

package com.aptech.aop2;
public class PersonTest {
	public static void main(String[] args) {
		IPerson proxy = new PersonProxy(new Person());
		proxy.eating();
		proxy.sleep();
	}
}

静态代理的弊端:

一个代理接口只能服务于一种类型的对象.对于稍大点的项目根本无法胜任.

3 解决方案2-动态代理

InvocationHandler:每一个动态代理类都必须实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的invoke方法来进行调用。

在JDK1.3之后加入了可协助开发的动态代理功能.不必为特定对象与方法编写特定的代理对象,使用动态代理,可以使得一个处理者(Handler)服务于各个对象.
一个处理者的类设计必须实现java.lang.reflect.InvocationHandler接口.
通过InvocationHandler接口实现的动态代理只能代理接口的实现类.

动态代理实现

1) 处理者(Handler)

public class DynaProxyHandler implements InvocationHandler {
	private Logger logger = Logger.getLogger(DynaProxyHandler.class);
	private Object target;
	//被代理对象
	public void setTarget(Object target) {
		this.target = target;
	}
	public Object invoke(Object proxy, Method method, Object[] args)
	              throws Throwable {
		logger.info("执行开始时间:" + new Date());
		Object result = method.invoke(target, args);
		logger.info("执行结束时间:" + new Date());
		return result;
		//返回method执行结果
	}
}

2) 生产代理对象的工厂

import java.lang.reflect.Proxy;
public class DynaProxyFactory {
	//obj为被代理对象
	public static Object getProxy(Object obj){
		DynaProxyHandler handler = new DynaProxyHandler();
		handler.setTarget(obj);
		return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
	}
}

3) 测试类

public class PersonTest {
	public static void main(String[] args) {
		IPerson person = (IPerson) DynaProxyFactory.getProxy(new Person());
		//返回代理类,代理类是JVM在内存中动态创建的,该类实现传入的接口数组的全部接口(的全部方法).
		person.eating();
		person.sleep();
	}
}

总结

以上就是本文关于Spring静态代理和动态代理代码详解的全部内容,希望对大家有所帮助。感兴趣的朋友可以继续参阅本站:

Spring常用配置及解析类说明

SpringMVC拦截器实现单点登录

Java编程实现springMVC简单登录实例

如有不足之处,欢迎留言指出。感谢朋友们对本站的支持!

相关文章

  • Spring Boot中扩展XML请求与响应的支持详解

    Spring Boot中扩展XML请求与响应的支持详解

    这篇文章主要给大家介绍了关于Spring Boot中扩展XML请求与响应的支持的相关资料,文中通过实例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2018-09-09
  • mybatis实现图书管理系统

    mybatis实现图书管理系统

    这篇文章主要为大家详细介绍了mybatis实现图书管理系统,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2020-06-06
  • Spring TaskScheduler使用实例解析

    Spring TaskScheduler使用实例解析

    这篇文章主要介绍了Spring TaskScheduler使用实例解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下
    2019-11-11
  • Struts2中ognl遍历数组,list和map方法详解

    Struts2中ognl遍历数组,list和map方法详解

    这篇文章主要介绍了Struts2中ognl遍历数组,list和map方法详解,需要的朋友可以参考下。
    2017-09-09
  • Java数组使用binarySearch()方法查找指定元素的实现

    Java数组使用binarySearch()方法查找指定元素的实现

    这篇文章主要介绍了Java数组使用binarySearch()方法查找指定元素的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2021-01-01
  • Java类锁、对象锁、私有锁冲突测试

    Java类锁、对象锁、私有锁冲突测试

    这篇文章主要介绍了Java类锁、对象锁、私有锁冲突测试,得出结论是加锁方法够成了竞争关系,同一时刻只能有一个方法能执行,需要的朋友可以参考下
    2014-10-10
  • Java多线程之线程状态的迁移详解

    Java多线程之线程状态的迁移详解

    线程状态迁移,又常被称作线程的生命周期,指的是线程从创建到终结需要经历哪些状态,什么情况下会出现哪些状态.线程的状态直接关系着并发编程的各种问题,本文就线程的状态迁移做一初步探讨,并总结在何种情况下会出现这些状态,需要的朋友可以参考下
    2021-06-06
  • 浅谈SpringBoot是如何实现日志的

    浅谈SpringBoot是如何实现日志的

    这篇文章主要介绍了浅谈SpringBoot是如何实现日志的,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2019-03-03
  • 谈谈在Java发送邮件中遇到的的问题

    谈谈在Java发送邮件中遇到的的问题

    本文介绍了在利用Java发送邮件过程中遇到的的两个问题,以及如何解决这两个问题。如果大家也遇到了这些问题,可以来参考借鉴。
    2016-08-08
  • springboot 使用Spring Boot Actuator监控应用小结

    springboot 使用Spring Boot Actuator监控应用小结

    本篇文章主要介绍了springboot 使用Spring Boot Actuator监控应用小结,小编觉得挺不错的,现在分享给大家,也给大家做个参考。一起跟随小编过来看看吧
    2018-02-02

最新评论