本节要点:

  • 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. Spring系列之手写注解与配置文件的解析

    目录 Spring系列之IOC的原理及手动实现 Spring系列之DI的原理及手动实现 Spring系列之AOP的原理及手动实现 引入 在前面我们已经完成了IOC,DI,AOP的实现,基本的功能都已经 ...

  2. 记一次SpringBoot 开发中所遇到的坑和解决方法

    记一次SpringBoot 开发中所遇到的坑和解决方法 mybatis返回Integer为0,自动转型出现空指针异常 当我们使用Integer去接受数据库中表的数据,如果返回的数据中为0,那么Inte ...

  3. 第7章 Linux上配置RAID

    7.1 RAID概念 RAID独立磁盘冗余阵列(Redundant Array of Independent Disks),RAID技术是将许多块硬盘设备组合成一个容量更大.更安全的硬盘组,可以将数据 ...

  4. Go Web:数据存储(3)——gob对象序列化

    序列化持久存储gob 1.内存存储 2.CSV文件存储 3.gob序列化存储 本篇文章仍然接前面的文章:内存存储,主要介绍将博客文章数据序列化持久到文件中. encoding/gob包用于编码器和解码 ...

  5. 翻译:replace into语句(已提交到MariaDB官方手册)

    本文为mariadb官方手册:REPLACE INTO的译文. 原文:https://mariadb.com/kb/en/replace/ 我提交到MariaDB官方手册的译文:https://mar ...

  6. iOS UITextfield只允许输入数字和字母,长度限制

    -(BOOL)textField:(UITextField *)textField shouldChangeCharactersInRange:(NSRange)range replacementSt ...

  7. 一个Fragment的实例

    @Override public void onActivityCreated(Bundle savedInstanceState) { // TODO Auto-generated method s ...

  8. 【转载】C#检测客户端输入的内容是否含有危险字符串

    用户在客户端提交的内容有时候并不可信,如果客户端提交的内容中含有危险字符串信息,则很有可能造成应用程序安全性问题,如SQL注入风险等.因此在接收客户端提交过来的数据后,我们首先需要判断数据中是否含有危 ...

  9. JQuery官方学习资料(译):类型

    类型     JavaScript提供了多个内置数据类型.除了这些,这份文档还将介绍一些虚拟类型,例如选择器.伪类.事件等. String 在JavaScript中字符串是一个不可变的对象,它包含无. ...

  10. SpringBoot的Autowierd失败

    通常是以下几种可能: 1.没有加@Service注解,或者是这个bean没有放在标注了@Configuration这个注解的类下. 2.SpringBoot启动类没有开启扫描 @ComponentSc ...