为什么我们使用动态代理

静态代理会让类变多了,多了代理类,工作量变大了,且不易扩展。比如我们上节课的例子,要实现不同的扩展方法就要编写不同的代理类,非常麻烦。
 

Proxy类的使用规则

Proxy提供了用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类。如果在程序中为一个或多个接口动态生成实现类,就可以使用 Proxy 来创建动态代理类。如果需要为一个或多个接口动态地创建实例,也可以使 Proxy 来创建动态代理实例。
Proxy提供了如下两个方法来创建动态代理类和动态代理实例:
  • static Class getProxyClass(ClassLoader loader, Class... interfaces): 创建一个动态代理类所对应的 Class对象,该代理类将实现interfaces 所指定的多个接口。第一个 ClassLoader 参数指定生成动态代理类的类加载器。(已过时)
  • static Object newProxyInstance(ClassLoader loader,Class[] interfaces, InvocationHandler h): 直接创建一个动态代理对象,代理对象的实现类实现了 interfaces 指定的系列接口 ,执行代理对象的每一个方法时都会被替换执行InvocationHandler 对象的 invoke 方法。
用实例来说明一下:
1,我们先定义一个接口:

package com.zmd.dynamicProxy;

/**
* @ClassName Person
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/5/16.
*/
public interface Person {
void walk();
void sayHello(String name);
}

2,定义自定义的InvocationHandler 继承InvocationHandler:

package com.zmd.dynamicProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; /**
* @ClassName MyInvocationHandler
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/5/16.
*/
public class MyInvocationHandler implements InvocationHandler {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("=======正在执行方法:"+ method.getName());
if (objects != null) {
System.out.println("下面为传入的参数:");
for (Object arg : objects) {
System.out.println(arg);
}
} else {
System.out.println("没有传入任何的参数");
}
return null;
}
}

3,调用测试:

package com.zmd.dynamicProxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; /**
* @ClassName MyInvocationTest
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/5/16.
*/
public class MyInvocationTest {
public static void main(String[] args) {
InvocationHandler invocationHandler = new MyInvocationHandler();
Person person = (Person) Proxy.newProxyInstance(Person.class.getClassLoader(),new Class[]{Person.class},invocationHandler);
person.walk();
person.sayHello("美女");
}
}

动态代理和AOP

根据前面介绍的 Proxy和InvocationHandler,实在很难看出这种动态代理的优势 下面介绍一种更实用的动态代理机制。
开发实际应用的软件系统时,通常会存在相同代码段重复出现的情况,在这种情况下,对于许多刚开始从事软件开发的人而言,他们的做法是:选中那些代码,Ctrl+C、Ctrl+V,如果仅仅从软件功能上来看,他们确实已经完成了软件开发。但是万一这段相同的逻辑需要改动呢?是不是要改很多地方呢?
用看电影举例:
1,首先创建电影功能接口:

package com.zmd.dynamicProxy.movieExample;

public interface Movie {
void play();
}
2,创建Movie的实现类(电影):
package com.zmd.dynamicProxy.movieExample;

public class ZhanlangMovie implements Movie {

    @Override
public void play() {
System.out.println("战狼,播放中...");
}
}

3,创建代理用的工具类,比如放电影之前和之后要干的事儿

package com.zmd.dynamicProxy.movieExample;

public class MovieUtil {
//play之前的方法
public static void before(){
System.out.println("PLAY 之前....");
}
//play之前的方法
public static void after(){
System.out.println("PLAY 之后....");
}
}

4,创建自定义代理类继承InvocationHandler,使用工具类为要代理接口实现类增加效果

package com.zmd.dynamicProxy.movieExample;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; public class MyInvocationHandler implements InvocationHandler {
private Movie movie; public MyInvocationHandler(Movie movie) {
this.movie = movie;
} @Override
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
//先调用工具类的方法(加广告)
MovieUtil.before();
//执行被包装的类的方法
Object result = method.invoke(movie, args);
//再调用工具类的方法(还是广告)
MovieUtil.after();
return result; //被包装的类的方法返回什么,这里也返回什么
}

}

5,利用代理类封装功能类,传入被代理的接口实现类(电影),返回真正给用户的电影

package com.zmd.dynamicProxy.movieExample;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; public class MovieFactory {
public static Movie getFactoryMovie(Movie movie){
InvocationHandler movieInvocationHandler = new MyInvocationHandler(movie);
Movie movie1 = (Movie) Proxy.newProxyInstance(movie.getClass().getClassLoader(),movie.getClass().getInterfaces(),movieInvocationHandler);
return movie1;
}
}

6、使用代理类

package com.zmd.dynamicProxy.movieExample;

public class FactoryMovieTest {
public static void main(String[] args) {
Movie zhanlang = MovieFactory.getFactoryMovie(new ZhanlangMovie());
zhanlang.play();
}
}

PLAY 之前....
战狼,播放中...
PLAY 之后....

 带泛型的代理,代理一切...

代理类  MyInvocationHandler.java 

package com.zmd.dynamicProxy.movieExample;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method; /**
* @ClassName MyInvocationHandler
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/5/17.
*/
public class MyInvocationHandler <T> implements InvocationHandler {
private T movie; public MyInvocationHandler(T movie) {
this.movie = movie;
} @Override
public Object invoke(Object o, Method method, Object[] args) throws Throwable {
//先调用工具类的方法(加广告)
MovieUtil.before();
//执行被包装的类的方法
Object result = method.invoke(movie, args);
//再调用工具类的方法(还是广告)
MovieUtil.after();
return result;
}
}

使用代理做的包装工具类 MovieFactory.java

package com.zmd.dynamicProxy.movieExample;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy; /**
* @ClassName MovieFactory
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/5/17.
*/
public class MovieFactory<T> {
public static <T> T getFactoryMovie(T movie){
InvocationHandler movieInvocationHandler = new MyInvocationHandler(movie);
T movie1 = (T) Proxy.newProxyInstance(movie.getClass().getClassLoader(),movie.getClass().getInterfaces(),movieInvocationHandler);
return movie1;
}
}

测试使用

音乐接口和实现类

package com.zmd.dynamicProxy.movieExample;

public interface Music {
void play();
}
package com.zmd.dynamicProxy.movieExample;

public class YueLiangZhiShang implements Music {
@Override
public void play() {
System.out.println("我在遥望,月亮之上...");
}
}

测试类

package com.zmd.dynamicProxy.movieExample;

/**
* @ClassName FactoryMovieTest
* @projectName: object1
* @author: Zhangmingda
* @description: XXX
* date: 2021/5/17.
*/
public class FactoryMovieTest {
public static void main(String[] args) {
Movie zhanlang = MovieFactory.getFactoryMovie(new ZhanlangMovie());
zhanlang.play();
Music yueliangzhishang = MovieFactory.getFactoryMovie(new YueLiangZhiShang());
yueliangzhishang.play();
}
}

PLAY 之前....
战狼,播放中...
PLAY 之后....
PLAY 之前....
我在遥望,月亮之上...
PLAY 之后....

java 编程基础 Class对象 反射:动态代理 和AOP:java.lang.reflect.Proxy:(Proxy.newProxyInstance(newProxyInstance​(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h))的更多相关文章

  1. java 编程基础 Class对象 反射 :数组操作java.lang.reflect.Array类

    java.lang.reflect包下还提供了Array类 java.lang.reflect包下还提供了Array类,Array对象可以代表所有的数组.程序可以通过使 Array 来动态地创建数组, ...

  2. java 编程基础 Class对象 反射 :参数反射

    方法参数反射 Java8在java.lang.reflect包下新增了Executable抽象基类,该对象代表可执行的类成员,该类派生了Constructor和Method两个子类.Executabl ...

  3. java 编程基础 Class对象 反射 :获取类的构造方法,方法,成员变量,内部类,外部类,父类,实现的接口,修饰符等...

    类 Class  每个类被加载之后,系统就会为该类生成一个对应的Class对象,通过该Class对象就可以访问到JVM中的这个类. 我们在Java中获取Class对象一般有三种方式: (1), 使用C ...

  4. java 编程基础 Class对象 反射:代理模式和静态代理

    生活中的代理 类(对象)代理模式 代理模式是面向对象编程中比较常见的设计模式. 1. 用户只关心接口功能,而不在乎谁提供了功能.上图中接口是 Subject 2. 接口真正实现者是上图的 RealSu ...

  5. 【Java核心技术】类型信息(Class对象 反射 动态代理)

    1 Class对象 理解RTTI在Java中的工作原理,首先需要知道类型信息在运行时是如何表示的,这是由Class对象来完成的,它包含了与类有关的信息.Class对象就是用来创建所有“常规”对象的,J ...

  6. 深入理解Java反射+动态代理

    答:   反射机制的定义: 是在运行状态中,对于任意的一个类,都能够知道这个类的所有属性和方法,对任意一个对象都能够通过反射机制调用一个类的任意方法,这种动态获取类信息及动态调用类对象方法的功能称为j ...

  7. Java基础加强-(注解,动态代理,类加载器,servlet3.0新特性)

    1.   Annotation注解 1.1.  Annotation概述 Annotation是JDK 5.0以后提供对元数据的支持,可以在编译.加载和运行时被读取,并执行相应的处理.所谓Annota ...

  8. Java动态代理-->Spring AOP

    引述要学习Spring框架的技术内幕,必须事先掌握一些基本的Java知识,正所谓“登高必自卑,涉远必自迩”.以下几项Java知识和Spring框架息息相关,不可不学(我将通过一个系列分别介绍这些Jav ...

  9. Java动态代理(AOP)

    目录 一.代理 1. 什么是代理? 2. 使用代理模式的作用 3. 实现代理的方式 二.静态代理 1. 模拟用户购买u盘 2. 静态代理的缺点 三.动态代理 四. JDK 动态代理 1. Invoca ...

随机推荐

  1. 关于阿里云图标的使用 iconfont

    iconfont 关于阿里云图标库使用的介绍 对于添加到网页中的iconfont可使用以下几种方式: 首先需要进入阿里云图标库官网进行对应的下载iconfont-阿里巴巴矢量图标库 将需要的图标加入到 ...

  2. Codeforces 1375F - Integer Game(交互)

    Codeforces 题面传送门 & 洛谷题面传送门 一个奇怪的做法. 首先我们猜测答案总是 First.考虑什么样的情况能够一步把对方一步干掉.方便起见我们假设 \(a<b<c\ ...

  3. Yii2 源码分析 入口文件执行流程

    Yii2 源码分析  入口文件执行流程 1. 入口文件:web/index.php,第12行.(new yii\web\Application($config)->run()) 入口文件主要做4 ...

  4. rabbit mq的php使用 amqp 的支持

    rabbit mq的php使用 php想要操作rabbit 需要扩展amqp 1,先查看自己的php版本 phpinfo() 接下来下载dll文件 地址http://pecl.php.net/pack ...

  5. C/C++ Qt StatusBar 底部状态栏应用

    Qt窗体中默认会附加一个QstatusBar组件,状态栏组件位于主窗体的最下方,其作用是提供一个工具提示功能,当程序中有提示信息是可以动态的显示在这个区域内,状态栏组件内可以增加任何Qt中的通用组件, ...

  6. SCRDet——对小物体和旋转物体更具鲁棒性的模型

    引言 明确提出了三个航拍图像领域内面对的挑战: 小物体:航拍图像经常包含很多复杂场景下的小物体. 密集:如交通工具和轮船类,在航拍图像中会很密集.这个DOTA数据集的发明者也提到在交通工具和轮船类的检 ...

  7. 14 - springboot的@Configuration、@Bean、@Import()、@ImportResource()、@Conditional说明

    1.@Configuration.@Bean.@Import().@ImportResource().@Conditional 分析源码的时候总会见到标题中的这几个注解,因此:弄一篇博客来说明一下吧, ...

  8. Flume(一)【概述】

    目录 一.Flume定义 二.Flume基础架构 1.Agent 2.Source 3.Sink 4.Channel 5.Event 一.Flume定义 ​ Flume是Cloudera公司提供的一个 ...

  9. 【STM8】外挂存储器W25Q16

    好像有几张图片被强制缩小了?看到这篇博客的人先对你们说声抱歉,我不知道怎么设置 文字就可以很长(文章宽度的全部),图片就只有文章宽度的2/3宽度 开新分页应该就是原始尺寸了,这点还是和大家说抱歉... ...

  10. java打jar包和运行jar包的两种方式

    java打jar包和运行jar包的两种方式更详细的打包方式请参考https://www.cnblogs.com/mq0036/p/8566427.html 一.java类不依赖第三方jar包以简单的一 ...