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简单登录实例

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

相关文章

  • 解决weblogic部署springboot项目步骤及可能会出现的问题

    解决weblogic部署springboot项目步骤及可能会出现的问题

    这篇文章主要介绍了解决weblogic部署springboot项目步骤及可能会出现的问题,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2021-07-07
  • SpringBoot整合WebSocket的客户端和服务端的实现代码

    SpringBoot整合WebSocket的客户端和服务端的实现代码

    这篇文章主要介绍了SpringBoot整合WebSocket的客户端和服务端的实现,本文通过实例代码给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友可以参考下
    2022-07-07
  • java利用Calendar类打印日历

    java利用Calendar类打印日历

    这篇文章主要为大家详细介绍了java利用Calendar类打印日历,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2019-07-07
  • 关于Java整合RocketMQ实现生产消费详解

    关于Java整合RocketMQ实现生产消费详解

    这篇文章主要介绍了关于Java整合RocketMQ实现生产消费详解,RocketMQ作为一款纯java、分布式、队列模型的开源消息中间件,支持事务消息、顺序消息、批量消息、定时消息、消息回溯等,需要的朋友可以参考下
    2023-05-05
  • Spring用代码来读取properties文件实例解析

    Spring用代码来读取properties文件实例解析

    这篇文章主要介绍了Spring用代码来读取properties文件实例解析,具有一定借鉴价值,需要的朋友可以参考下
    2018-01-01
  • java项目实现图片等比缩放

    java项目实现图片等比缩放

    这篇文章主要为大家详细介绍了java项目实现图片等比缩放,文中示例代码介绍的非常详细,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2022-04-04
  • MyBatis中关于SQL的写法总结

    MyBatis中关于SQL的写法总结

    这篇文章主要介绍了MyBatis中关于SQL的写法总结,具有很好的参考价值,希望对大家有所帮助。如有错误或未考虑完全的地方,望不吝赐教
    2022-08-08
  • Java接收前端请求体的多种方式总结

    Java接收前端请求体的多种方式总结

    这篇文章主要给大家介绍了关于Java接收前端请求体的多种方式,文中通过代码介绍的非常详细,对大家学习或者Java具有一定的参考学习价值,需要的朋友可以参考下
    2023-08-08
  • Java使用join方法暂停当前线程

    Java使用join方法暂停当前线程

    这篇文章主要为大家详细介绍了Java使用join方法暂停当前线程,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
    2017-04-04
  • springboot druid数据库连接池连接失败后一直重连的解决方法

    springboot druid数据库连接池连接失败后一直重连的解决方法

    本文主要介绍了springboot druid数据库连接池连接失败后一直重连的解决方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
    2022-04-04

最新评论