本节要点:

  • Java静态代理
  • Jdk动态代理

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

在传统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  维护工作量巨大

解决方案1-静态代理

  • 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("正在吃饭中");

         }

}
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-动态代理

  • 在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();

         }

}

4)     将2)和3)合并的写法

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; public class PersonTest { public static void main(String[] args) {
//是我们要代理的真实对象
IPerson person1 = new Person();
//我们要代理哪个真实对象,就将该对象传进去,最后是通过该真实对象来调用其方法的
InvocationHandler handler = new DynaProxyHandler(person1);
/*
* 通过Proxy的newProxyInstance方法来创建我们的代理对象,我们来看看其三个参数
* 第一个参数 handler.getClass().getClassLoader() ,我们这里使用handler这个类的ClassLoader对象来加载我们的代理对象
* 第二个参数person1.getClass().getInterfaces(),我们这里为代理对象提供的接口是真实对象所实行的接口,表示我要代理的是该真实对象,这样我就能调用这组接口中的方法了
* 第三个参数handler, 我们这里将这个代理对象关联到了上方的 InvocationHandler 这个对象上
*/
IPerson person = (IPerson) Proxy.newProxyInstance(handler.getClass().getClassLoader(), person1.getClass().getInterfaces(), handler); person.eating();
person.sleep();
}
}

我在学习 Java 的动态代理的时候,一直在使用 Proxy.newProxyInstance 方法生成代理的时候报错(如标题)。

我使用各种方法都无法解决这个问题,后来我直接用别人博客上的代码跑了一下,结果成功了。

于是我对比两个代码之间的差别,发现问题可能处在委托对象上面。

我写的代码委托对象是继承一个虚基类,而不是一个接口,于是我把我的代码改了一下,于是乎就跑起来了。。。

总结:要使用动态代理,用来生成代理的委托对象必须是一个接口。

spring静态代理和动态代理的更多相关文章

  1. java中代理,静态代理,动态代理以及spring aop代理方式,实现原理统一汇总

    若代理类在程序运行前就已经存在,那么这种代理方式被成为 静态代理 ,这种情况下的代理类通常都是我们在Java代码中定义的. 通常情况下, 静态代理中的代理类和委托类会实现同一接口或是派生自相同的父类. ...

  2. java:struts框架2(方法的动态和静态调用,获取Servlet API三种方式(推荐IOC(控制反转)),拦截器,静态代理和动态代理(Spring AOP))

    1.方法的静态和动态调用: struts.xml: <?xml version="1.0" encoding="UTF-8"?> <!DOCT ...

  3. Spring专题1: 静态代理和动态代理

    合集目录 Spring专题1: 静态代理和动态代理 为什么需要代理模式? 代理对象处于访问者和被访问者之间,可以隔离这两者之间的直接交互,访问者与代理对象打交道就好像在跟被访者者打交道一样,因为代理者 ...

  4. spring——AOP(静态代理、动态代理、AOP)

    一.代理模式 代理模式的分类: 静态代理 动态代理 从租房子开始讲起:中介与房东有同一的目标在于租房 1.静态代理 静态代理角色分析: 抽象角色:一般使用接口或者抽象类来实现(这里为租房接口) pub ...

  5. spring的静态代理和动态代理

    Java静态代理 Jdk动态代理 java代理模式 即Proxy Pattern,23种java常用设计模式之一.代理模式的定义:对其他对象提供一种代理以控制对这个对象的访问. 原理: 代理模式的主要 ...

  6. Spring 静态代理和动态代理

    现在我们来模拟一下,某位学生去考试. 假设他(小明)正常的考试. 运行结果:        结果: 突然某一天,他睡过头了,来不急去考试,所有他打算叫另一个人(Cheater)去代替他考试. 运行结果 ...

  7. Spring AOP里的静态代理和动态代理,你真的了解嘛?

    什么是代理? 为某一个对象创建一个代理对象,程序不直接用原本的对象,而是由创建的代理对象来控制原对象,通过代理类这中间一层,能有效控制对委托类对象的直接访问,也可以很好地隐藏和保护委托类对象,同时也为 ...

  8. Atitit 代理CGLIB 动态代理 AspectJ静态代理区别

    Atitit 代理CGLIB 动态代理 AspectJ静态代理区别 1.1. AOP 代理主要分为静态代理和动态代理两大类,静态代理以 AspectJ 为代表:而动态代理则以 spring AOP 为 ...

  9. 【Java】代处理?代理模式 - 静态代理,动态代理

    >不用代理 有时候,我希望在一些方法前后都打印一些日志,于是有了如下代码. 这是一个处理float类型加法的方法,我想在调用它前打印一下参数,调用后打印下计算结果.(至于为什么不直接用+号运算, ...

随机推荐

  1. Mybatis解析mapper

    众所周知,接口是不能被实例化的,但是日常开发中,我们经常能直接使用dao层对象的方法,这又是为什么呢. 带着这些问题,我们看下mybatis内部做了那些操作. Mapper解析 上文我们描述了myba ...

  2. python 时间模块time,datetime

    模块(module)是 Python 中非常重要的东西,你可以把它理解为 Python 的扩展工具.换言之,Python 默认情况下提供了一些可用的东西,但是这些默认情况下提供的还远远不能满足编程实践 ...

  3. 浅谈基于WOPI协议实现跨浏览器的Office在线编辑解决方案

    如今,基于Web版的Office 在线预览与编辑功能已成为一种趋势,而关于该技术的实现却成为了国内大部份公司的技术挑战,挑战主要存在于两方面: 其一:目前国内乃至微软本身,还没有相对较为完善的解决方案 ...

  4. MyBatis源码解析(六)——DataSource数据源模块之池型数据源

    原创作品,可以转载,但是请标注出处地址:http://www.cnblogs.com/V1haoge/p/6675674.html 1 回顾 上一文中解读了MyBatis中非池型数据源的源码,非池型也 ...

  5. AFNetworking封装-项目使用

    本篇博客是接着上一篇AFNetworking源码解析的后续,如果想对AFNetworking源码有所了解. 请读一下https://www.cnblogs.com/guohai-stronger/p/ ...

  6. 《C#并发编程经典实例》学习笔记—2.1 暂停一段时间

    问题: 需要让程序(以异步方式)等待一段时间. 解决方案:Task类的静态函数Delay,返回Task对象 在github开源项目dotnet/coreclr,找到Task.cs有关Delay方法的源 ...

  7. Redis学习笔记(1)-安装Oracle VM VirtualBox

    Oracle VM VirtualBox官网网址 打开安装包网址界面,如下所示,点击截图红框. 下载完成后,点击exe文件,不停的点击下一步. 因为是使用MarkDown编辑器书写的尝试,所以写的简单 ...

  8. 安装Ubuntu的Mozilla Firefox的Adobe Flash Player时学习/lib、/usr/lib、/usr/local/lib的区别

    想对比一下Ubuntu和windows下视频效果体验的区别.安装了Ubuntu新版14.04.在之前的学习工程中,从来没想过使用虚拟机里的火狐浏览器看视频浏览网页,所以还真没有安装Flash的Linu ...

  9. 【Tomcat】Tomcat工作原理

    Tomcat 总体结构 Tomcat 的结构很复杂,但是 Tomcat 也非常的模块化,找到了 Tomcat 最核心的模块,您就抓住了 Tomcat 的“七寸”.下面是 Tomcat 的总体结构图: ...

  10. Maven(五)Eclipse配置Maven插件

    较新版本的Eclipse内置Maven插件 1. 设置installation 一般不适用内置的 指定核心程序的位置 2. 设置user settings 指定本地仓库的位置 1.如果setting. ...