为什么我们使用动态代理

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

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. javascript-初级-day04js数据类型

    day01-js数据类型 <!DOCTYPE HTML> <html> <head> <meta http-equiv="Content-Type& ...

  2. 如何理解Casbin的权限控制

    概念: Casbin是什么? Casbin是一个访问控制框架,可以支持多种访问控制模型(如ACL.RBAC.ABAC等) 目的: 我们最终想要实现的效果: 可以控制某一个人/角色(sub)能否对某个资 ...

  3. 洛谷 P5249 - [LnOI2019]加特林轮盘赌(期望 dp+高斯消元)

    题面传送门 期望真 nm 有意思,所以蒟蒻又来颓期望辣 先特判掉 \(P_0=0\) 的情况,下面假设 \(P_0\ne 0\). 首先注意到我们每次将加特林对准一个人,如果这个人被毙掉了,那么相当于 ...

  4. 【R】调整ggplot图例大小

    图例太多时,会挤压正图,显得正图展示区域很小,这时有必要缩小图例. ################# # 减小ggplot图例 ################# library(ggplot2) ...

  5. R shinydashboard ——1. 基本用法

    shiny和shinydashboard使用虽然简单,但控件众多,需及时总结归纳. install.packages("shinydashboard") shinydashboar ...

  6. perl 获取目录信息

    1 #!/usr/bin/perl -w 2 use strict; 3 use FindBin qw($Bin $Script); 4 5 my $rp=$Bin; 6 print "th ...

  7. R 多图间距调整

    在R中多图画到一起的时候,各图间距通常默认的较远. 如下图: 1 par(mfcol=c(2,1)) 2 plot(1:100) 3 plot(1:100) 调整图片间距这时我们要用到par()函数中 ...

  8. Excel-电话号码隐藏某几个数为*,起到保护信息作用;

    9.电话号码隐藏某几个数为*,起到保护信息作用: 方法一: =SUBSTITUTE(AG2,MID(AG2,4,5),"*****") 解释函数: MID(目标字符串,裁剪起始位置 ...

  9. MapReduce08 数据清洗(ETL)和压缩

    目录 数据清洗(ETL) ETL清洗案例 需求 需求分析 实现代码 编写WebLogMapper类 编写WebLogDriver类 打包到集群运行 压缩 概念 MR支持的压缩编码 压缩算法对比 压缩性 ...

  10. 【STM32】基于正点原子『探索者』开发板的烧录

    项目需要一个功能,开发板范例正好有,就买了一块,不过还是有点贵 我手边没有J-Link 用的都是串口烧录 烧录时,先打开右上的开关 如果是仿真器烧录,它无法供电,需要接12V适配器或是杜邦线供电 然后 ...