反射的应用:动态代理
7
15-1 Java
反射机制概述
Reflection
(反射)是被视为
动态语言
的关键,反射机制允许程序在执行期
借助于
Reflection API
取得任何类的内部信息,并能直接操作任意对象的内
部属性及方法。
加载完类之后,在堆内存的方法区中就产生了一个
Class
类型的对象(一个
类只有一个
Class
对象),这个对象就包含了完整的类的结构信息。我们可
以通过这个对象看到类的结构。
这个对象就像一面镜子,透过这个镜子看
到类的结构,所以,我们形象的称之为:
反射
。
15.1 Java
反射机制概述
Java Reflection
正常方式:
反射方式:
引入需要的
”
包类
”
名称
通过
new
实例化
取得实例化对象
实例化对象
getClass()
方法
得到完整的“包类”名称
15.1 Java
反射机制概述
补充:动态语言
vs
静态语言
1
、动态语言
是一类在运行时可以改变其结构的语言:例如新的函数、对象、甚至代码可以
被引进,已有的函数可以被删除或是其他结构上的变化。通俗点说就是
在运
行时代码可以根据某些条件改变自身结构
。
主要动态语言:
Object-C
、
C#
、
JavaScript
、
PHP
、
Python
、
Erlang
。
2
、静态语言
与动态语言相对应的,
运行时结构不可变的语言就是静态语言。如
Java
、
C
、
C++
。
Java
不是动态语言,但
Java
可以称之为
“准动态语言”
。即
Java
有一定的动
态性,我们可以利用反射机制、字节码操作获得类似动态语言的特性。
Java
的动态性让编程的时候更加灵活!
15.1 Java
反射机制概述
Java
反射机制研究及应用
Java
反射机制提供的功能
在运行时判断任意一个对象所属的类
在运行时构造任意一个类的对象
在运行时判断任意一个类所具有的成员变量和方法
在运行时获取泛型信息
在运行时调用任意一个对象的成员变量和方法
在运行时处理注解
生成动态代理
15.1 Java
反射机制概述
反射相关的主要
API
java.lang.Class
:
代表一个类
java.lang.reflect.Method:
代表类的方法
java.lang.reflect.Field:
代表类的成员变量
java.lang.reflect.Constructor:
代表类的构造器
… …
15-2
理解
Class
类并
获取
Class
的实例
15.2
理解
Class
类并获取
Class
的实例
Class
类
在
Object
类中定义了以下的方法,此方法
将被所有子类继承:
●
public final Class getClass()
以上的方法返回值的类型是一个
Class
类,
此类是
Java
反射的源头,实际上所谓反射
从程序的运行结果来看也很好理解,即:
可以通过对象反射求出类的名称。
15.2
理解
Class
类并获取
Class
的实例
Class
类
对象照镜子后可以得到的信息:某个类的属性、方法和构造器、某个类到底实现了哪些接
口。对于每个类而言,
JRE
都为其保留一个不变的
Class
类型的对象。一个
Class
对象包含
了特定某个结构
(class/interface/enum/annotation/primitive type/void/[])
的有关信息。
Class
本身也是一个类
Class
对象只能由系统建立对象
一个加载的类在
JVM
中只会有一个
Class
实例
一个
Class
对象对应的是一个加载到
JVM
中的一个
.class
文件
每个类的实例都会记得自己是由哪个
Class
实例所生成
通过
Class
可以完整地得到一个类中的所有被加载的结构
Class
类是
Reflection
的根源,针对任何你想动态加载、运行的类,唯有先获得相应的
Class
对象
Class
类的常用方法
方法名
功能说明
static Class forName(String name)
返回指定类名
name
的
Class
对象
Object newInstance()
调用缺省构造函数,返回该
Class
对象的一个实例
getName()
返回此
Class
对象所表示的实体(类、接口、数组类、基本类型
或
void
)名称
Class getSuperClass()
返回当前
Class
对象的父类的
Class
对象
Class [] getInterfaces()
获取当前
Class
对象的接口
ClassLoader getClassLoader()
返回该类的类加载器
Class getSuperclass()
返回表示此
Class
所表示的实体的超类的
Class
Constructor[] getConstructors()
返回一个包含某些
Constructor
对象的数组
Field[] getDeclaredFields()
返回
Field
对象的一个数组
Method getMethod(String
name,Class … paramTypes)
返回一个
Method
对象,此对象的形参类型为
paramType
15.2
理解
Class
类并获取
Class
的实例
15.2
理解
Class
类并获取
Class
的实例
反射的应用举例
• String str = "test4.Person";
• Class clazz = Class.forName(str);
• Object obj = clazz.newInstance();
• Field field = clazz.getField("name");
• field.set(obj, "Peter");
• Object name = field.get(obj);
• System.out.println(name);
注:
test4.Person
是
test4
包下的
Person
类
15.2
理解
Class
类并获取
Class
的实例
获取
Class
类的实例
(
四种方法
)
1
)
前提:
若已知具体的类,通过类的
class
属性获取,该方法最为安全可靠,
程序性能最高
实例:
Class clazz = String.class;
2
)
前提:
已知某个类的实例,调用该实例的
getClass()
方法获取
Class
对象
实例:
Class clazz = “www.atguigu.com”.getClass();
3
)
前提:
已知一个类的全类名,且该类在类路径下,可通过
Class
类的静态方
法
forName()
获取,可能抛出
ClassNotFoundException
实例:
Class clazz = Class.forName(“java.lang.String”);
4
)其他方式
(
不做要求
)
ClassLoader cl = this.getClass().getClassLoader();
Class clazz4 = cl.loadClass(“
类的全类名
”);
15.2
理解
Class
类并获取
Class
的实例
哪些类型可以有
Class
对象?
(
1
)
class
:
外部类,成员
(
成员内部类,静态内部类
)
,局部内部类,匿名内部类
(
2
)
interface
:接口
(
3
)
[]
:数组
(
4
)
enum
:枚举
(
5
)
annotation
:注解
@interface
(
6
)
primitive type
:基本数据类型
(
7
)
void
15.2
理解
Class
类并获取
Class
的实例
Class
c1
= Object.
class
;
Class
c2
= Comparable.
class
;
Class
c3
= String[].
class
;
Class
c4
=
int
[][].
class
;
Class
c5
= ElementType.
class
;
Class
c6
=
Override
.
class
;
Class
c7
=
int
.
class
;
Class
c8
=
void
.
class
;
Class
c9
= Class.
class
;
int
[]
a
=
new int
[10];
int
[]
b
=
new int
[100];
Class
c10
=
a
.getClass();
Class
c11
=
b
.getClass();
//
只要元素类型与维度一样,就是同一个
Class
System.
out
.println(
c10
==
c11
);
15-3
类的加载
与
ClassLoader
的理解
了解:类的加载过程
类的加载
(Load)
类的链接
(Link)
当程序主动使用某个类时,如果该类还未被加载到内存中,则系统会通过
如下三个步骤来对该类进行初始化。
类的初始化
(Initialize)
将类的
class
文件读入
内存,并为之创建一
个
java.lang.Class
对
象。此过程由类加载
器完成
将类的二进制数
据合并到
JRE
中
JVM
负责对类
进行初始化
15.3
类的加载与
ClassLoader
的理解
15.3
类的加载与
ClassLoader
的理解
加载:将
class
文件字节码内容加载到内存中,并将这些静态数据转换成方法区的运行时
数据结构,然后生成一个代表这个类的
java.lang.Class
对象,作为方法区中类数据的访问
入口(即引用地址)。所有需要访问和使用类数据只能通过这个
Class
对象。这个加载的
过程需要类加载器参与。
链接:将
Java
类的二进制代码合并到
JVM
的运行状态之中的过程。
验证:确保加载的类信息符合
JVM
规范,例如:以
cafe
开头,没有安全方面的问题
准备:正式为类变量(
static
)分配内存并
设置类变量默认初始值
的阶段,这些内存
都将在方法区中进行分配。
解析:虚拟机常量池内的符号引用(常量名)替换为直接引用(地址)的过程。
初始化:
执行
类构造器
()
方法的过程。
类构造器
()
方法是由编译期自动收集类中
所有类变量的赋值动作和静态代码块中的语句合并产生的。
(类构造器是构造类信
息的,不是构造该类对象的构造器)。
当初始化一个类的时候,如果发现其父类还没有进行初始化,则需要先触发其父类
的初始化。
虚拟机会保证一个类的
()
方法在多线程环境中被正确加锁和同步。
15.3
类的加载与
ClassLoader
的理解
public class
ClassLoadingTest {
public static void
main(String[]
args
) {
System.
out
.println(A.
m
);
}
}
class
A {
static
{
m
= 300;
}
static int
m
= 100;
}
//
第二步:链接结束后
m=0
//
第三步:初始化后,
m
的值由
()
方法执行决定
//
这个
A
的类构造器
()
方法由类变量的赋值和静态代码块中的语句按照顺序合并
产生,类似于
// (){
// m = 300;
// m = 100;
// }
15.3
类的加载与
ClassLoader
的理解
了解:什么时候会发生类初始化?
类的主动引用(一定会发生类的初始化)
当虚拟机启动,先初始化
main
方法所在的类
new
一个类的对象
调用类的静态成员(除了
final
常量)和静态方法
使用
java.lang.reflect
包的方法对类进行反射调用
当初始化一个类,如果其父类没有被初始化,则先会初始化它的父类
类的被动引用(不会发生类的初始化)
当访问一个静态域时,只有真正声明这个域的类才会被初始化
当通过子类引用父类的静态变量,不会导致子类初始化
通过数组定义类引用,不会触发此类的初始化
引用常量不会触发此类的初始化(常量在链接阶段就存入调用类的常
量池中了)
public class
ClassLoadingTest {
public static void
main(String[]
args
) {
//
主动引用:一定会导致
A
和
Father
的初始化
// A a = new A();
// System.out.println(A.m);
// Class.forName("com.atguigu.java2.A");
//
被动引用
A[]
array
=
new
A[5];
//
不会导致
A
和
Father
的
初始化
// System.out.println(A.b);//
只会初始化
Father
// System.out.println(A.M);//
不会导致
A
和
Father
的初始化
}
static
{
System.
out
.println(
"main
所在的类
"
);
}
}
class
Father {
static int
b
= 2;
static
{
System.
out
.println(
"
父类被加载
"
);
}
}
class
A
extends
Father {
static
{
System.
out
.println(
"
子类被加载
"
);
m
= 300;
}
static int
m
= 100;
static final int
M
= 1;
}
15.3
类的加载与
ClassLoader
的理解
15.3
类的加载与
ClassLoader
的理解
类加载器的作用:
类加载的作用:
将
class
文件字节码内容加载到内存中,并将这些静态数据
转换成方
法区的运行时数据结构
,然后在堆中生成一个代表这个类的
java.lang.Class
对象,作为
方法区中类数据的访问入口。
类缓存:
标准的
JavaSE
类加载器可以按要求查找类,但一旦某个类被加载到类加载器
中,它将维持加载(缓存)一段时间。不过
JVM
垃圾回收机制可以回收这些
Class
对象。
15.3
类的加载与
ClassLoader
的理解
了解:
ClassLoader
类加载器作用是用来把类
(class)
装载进内存的。
JVM
规范定义了如下类型的
类的加载器。
引导类加载器
:用
C++
编写的,是
JVM
自带的类
加载器,
负责
Java
平台核心库
,用来装载核心类
库。该加载器无法直接获取
扩展类加载器
:负责
jre/lib/ext
目录下的
jar
包或
–
D java.ext.dirs
指定目录下的
jar
包装入工作库
系统类加载器
:负责
java –classpath
或
–D
java.class.path
所指的目录下的类与
jar
包装入工
作 ,是最常用的加载器
15.3
类的加载与
ClassLoader
的理解
• //1.
获取一个系统类加载器
•
ClassLoader classloader = ClassLoader.getSystemClassLoader();
•
System.out.println(classloader);
• //2.
获取系统类加载器的父类加载器,即扩展类加载器
•
classloader = classloader.getParent();
•
System.out.println(classloader);
• //3.
获取扩展类加载器的父类加载器,即引导类加载器
•
classloader = classloader.getParent();
•
System.out.println(classloader);
• //4.
测试当前类由哪个类加载器进行加载
•
classloader = Class.forName("exer2.ClassloaderDemo").getClassLoader();
•
System.out.println(classloader);
15.3
类的加载与
ClassLoader
的理解
• //5.
测试
JDK
提供的
Object
类由哪个类加载器加载
•
classloader =
•
Class.forName("java.lang.Object").getClassLoader();
•
System.out.println(classloader);
• //*6.
关于类加载器的一个主要方法:
getResourceAsStream(String str):
获取类路
径下的指定文件的输入流
•
InputStream in = null;
•
in = this.getClass().getClassLoader().getResourceAsStream("exer2\\test.properties");
•
System.out.println(in);
15-4
创建运行时类的对象
创建类的对象:
调用
Class
对象的
newInstance()
方法
要 求:
1
)类必须有一个无参数的构造器。
2
)类的构造器的访问权限需要足够。
难道没有无参的构造器就不能创建对象了吗?
不是!只要在操作的时候明确的调用类中的构造器,并将参数传递进去之后,才可以实例化操作。
步骤如下:
1
)通过
Class
类的
getDeclaredConstructor(Class … parameterTypes)
取得本类的指定形参类
型的构造器
2
)向构造器的形参中传递一个对象数组进去,里面包含了构造器中所需的各个参数。
3
)通过
Constructor
实例化对象。
有了
Class
对象,能做什么?
以上是反射机制应用最多的地方。
15.4
创建运行时类的对象
15.4
创建运行时类的对象
//1.
根据全类名获取对应的
Class
对象
String name = “atguigu.java.Person";
Class clazz = null;
clazz = Class.forName(name);
//2.
调用指定参数结构的构造器,生成
Constructor
的实例
Constructor con = clazz.getConstructor(String.class,Integer.class);
//3.
通过
Constructor
的实例创建对应类的对象,并初始化类属性
Person p2 = (Person) con.newInstance("Peter",20);
System.out.println(p2);
15-5
获取运行时类的完
整结构
15.5
获取运行时类的完整结构
通过反射获取运行时类的完整结构
Field
、
Method
、
Constructor
、
Superclass
、
Interface
、
Annotation
实现的全部接口
所继承的父类
全部的构造器
全部的方法
全部的
Field
15.5
获取运行时类的完整结构
使用反射可以取得:
1.
实现的全部接口
public Class<?>[] getInterfaces()
确定此对象所表示的类或接口实现的接口。
2.
所继承的父类
public Class<? Super T> getSuperclass()
返回表示此
Class
所表示的实体(类、接口、基本类型)的父类的
Class
。
15.5
获取运行时类的完整结构
3.
全部的构造器
public Constructor[] getConstructors()
返回此
Class
对象所表示的类的所有
public
构造方法。
public Constructor[] getDeclaredConstructors()
返回此
Class
对象表示的类声明的所有构造方法。
Constructor
类中:
取得修饰符
:
public int getModifiers();
取得方法名称
:
public String getName();
取得参数的类型:
public Class<?>[] getParameterTypes();
15.5
获取运行时类的完整结构
4.
全部的方法
public Method[] getDeclaredMethods()
返回此
Class
对象所表示的类或接口的全部方法
public Method[] getMethods()
返回此
Class
对象所表示的类或接口的
public
的方法
Method
类中:
public Class<?> getReturnType()
取得全部的返回值
public Class<?>[] getParameterTypes()
取得全部的参数
public int getModifiers()
取得修饰符
public Class<?>[] getExceptionTypes()
取得异常信息
15.5
获取运行时类的完整结构
5.
全部的
Field
public Field[] getFields()
返回此
Class
对象所表示的类或接口的
public
的
Field
。
public Field[] getDeclaredFields()
返回此
Class
对象所表示的类或接口的全部
Field
。
Field
方法中:
public int getModifiers()
以整数形式返回此
Field
的修饰符
public Class<?> getType()
得到
Field
的属性类型
public String getName()
返回
Field
的名称。
6. Annotation
相关
get Annotation(Class annotationClass)
getDeclaredAnnotations
()
7.
泛型相关
获取父类泛型类型:
Type getGenericSuperclass()
泛型类型:
ParameterizedType
获取实际的泛型类型参数数组:
getActualTypeArguments()
8.
类所在的包
Package getPackage()
15.5
获取运行时类的完整结构
15.5
获取运行时类的完整结构
小 结:
1.
在实际的操作中,取得类的信息的操作代码,并不会经常开发。
2.
一定要熟悉
java.lang.reflect
包的作用,反射机制。
3.
如何取得属性、方法、构造器的名称,修饰符等。
15-6
调用运行时类的指
定结构
通过反射,调用类中的方法,通过
Method
类完成。步骤:
1.
通过
Class
类的
getMethod(String name,Class…parameterTypes)
方法取得
一个
Method
对象,并设置此方法操作时所需要的参数类型。
2.
之后使用
Object invoke(Object obj, Object[] args)
进行调用,并向方法中
传递要设置的
obj
对象的参数信息。
Class.forName()
getMethod(“sayHello”)
invoke()
1.
实例化
Class
2.
找到
sayHello()
3.
调用方法
Person
+sayHello():void
1.
调用指定方法
15.6
调用运行时类的指定结构
15.6
调用运行时类的指定结构
Object invoke(Object obj, Object … args)
说明:
1.Object
对应原方法的返回值,若原方法无返回值,此时返回
null
2.
若原方法若为静态方法,此时形参
Object obj
可为
null
3.
若原方法形参列表为空,则
Object[] args
为
null
4.
若原方法声明为
private,
则需要在调用此
invoke()
方法前,显式调用
方法对象的
setAccessible(true)
方法,将可访问
private
的方法。
15.6
调用运行时类的指定结构
2.
调用指定属性
在反射机制中,可以直接通过
Field
类操作类中的属性,通过
Field
类提供的
set()
和
get()
方法就可以完成设置和取得属性内容的操作。
public Field getField(String name)
返回此
Class
对象表示的类或接口的指定的
public
的
Field
。
public Field getDeclaredField(String name)
返回此
Class
对象表示的类或接口的
指定的
Field
。
在
Field
中:
public Object get(Object obj)
取得指定对象
obj
上此
Field
的属性内容
public void set(Object obj,Object value)
设置指定对象
obj
上此
Field
的属性内容
15.6
调用运行时类的指定结构
关于
setAccessible
方法的使用
Method
和
Field
、
Constructor
对象都有
setAccessible()
方法。
setAccessible
启动和禁用访问安全检查的开关。
参数值为
true
则指示反射的对象在使用时应该取消
Java
语言访问检查。
提高反射的效率。如果代码中必须用反射,而该句代码需要频繁的被
调用,那么请设置为
true
。
使得原本无法访问的私有成员也可以访问
参数值为
false
则指示反射的对象应该实施
Java
语言访问检查。
15-7
反射的应用:动态代理
15.7
反射的应用:动态代理
代理设计模式的原理
:
使用一个代理将对象包装起来
,
然后用该代理对象取代原始对象。任何对原
始对象的调用都要通过代理。代理对象决定是否以及何时将方法调用转到原
始对象上。
之前为大家讲解过代理机制的操作,属于静态代理,特征是代理类和目标
对象的类都是在编译期间确定下来,不利于程序的扩展。同时,每一个代
理类只能为一个接口服务,这样一来程序开发中必然产生过多的代理。
最
好可以通过一个代理类完成全部的代理功能。
15.7
反射的应用:动态代理
动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时
根据需要动态创建目标类的代理对象。
动态代理使用场合
:
调试
远程方法调用
动态代理相比于静态代理的优点:
抽象角色中(接口)声明的所有方法都被转移到调用处理器一个集中的方法中
处理,这样,我们可以更加灵活和统一的处理众多的方法。
Proxy
:专门完成代理的操作类,是所有动态代理类的父类。通过此类为一
个或多个接口动态地生成实现类。
提供用于创建动态代理类和动态代理对象的静态方法
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces)
创建
一个动态代理类所对应的
Class
对象
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
InvocationHandler h)
直接创建一个动态代理对象
Java
动态代理相关
API
类加载器
得到被代理类实
现的全部接口
得到
InvocationHandler
接
口的实现类实例
15.7
反射的应用:动态代理
动态代理步骤
1.
创建一个实现接口
InvocationHandler
的类,它必须实现
invoke
方
法,以完成代理的具体操作。
public Object invoke(Object theProxy, Method method, Object[] params)
throws Throwable
{
try{
Object retval = method.invoke(targetObj, params);
// Print out the result
System.out.println(retval);
return retval;
}catch (Exception exc){}
}
代理类的对象
要调用的方法
方法调用时所
需要的参数
15.7
反射的应用:动态代理
动态代理步骤
2.
创建被代理的类以及接口
Subject
RealSubject
implements
say(String name,int age)
15.7
反射的应用:动态代理
15.7
反射的应用:动态代理
动态代理步骤
3.
通过
Proxy
的静态方法
newProxyInstance(ClassLoader loader, Class[] interfaces, InvocationHandler h)
创建
一个
Subject
接口代理
RealSubject target = new RealSubject();
// Create a proxy to wrap the original implementation
DebugProxy proxy = new DebugProxy(target);
// Get a reference to the proxy through the Subject interface
Subject sub = (Subject) Proxy.newProxyInstance(
Subject.class.getClassLoader(),new Class[] { Subject.class }, proxy);
15.7
反射的应用:动态代理
动态代理步骤
4.
通过
Subject
代理调用
RealSubject
实现类的方法
String info = sub.say(“Peter", 24);
System.out.println(info);
动态代理与
AOP
(
Aspect Orient Programming)
前面介绍的
Proxy
和
InvocationHandler
,很难看出这种动态代理的优势,下
面介绍一种更实用的动态代理机制
相同的代
码段
相同的代
码段
相同的代
码段
代码段
2
代码段
3
代码段
1
通过复制、
粘贴的部分
15.7
反射的应用:动态代理
动态代理与
AOP
(
Aspect Orient Programming)
调用方法
调用方法
调用方法
代码段
2
代码段
3
代码段
1
相同的代
码段
方法A
改进后的说明:代码段
1
、代码段
2
、代码段
3
和深色代码段分离开了,但代码段
1
、
2
、
3
又和
一个特定的方法
A
耦合了!最理想的效果是:代码块
1
、
2
、
3
既可以执行方法
A
,又无须在程序
中以硬编码的方式直接调用深色代码的方法
15.7
反射的应用:动态代理
15.7
反射的应用:动态代理
动态代理与
AOP
(
Aspect Orient Programming)
public interface Dog{
void info();
void run();
}
public class HuntingDog implements Dog{
public void info(){
System.out.println("我是一只猎狗");
}
public void run(){
System.out.println("我奔跑迅速");
}
}
15.7
反射的应用:动态代理
动态代理与
AOP
(
Aspect Orient Programming)
public class DogUtil{
public void method1(){
System.out.println("=====
模拟通用方法一
=====");
}
public void method2(){
System.out.println("=====
模拟通用方法二
=====");
}
}
15.7
反射的应用:动态代理
动态代理与
AOP
(
Aspect Orient Programming)
public class MyInvocationHandler implements InvocationHandler{
//
需要被代理的对象
private Object target;
public void setTarget(Object target){
this.target = target;}
//
执行动态代理对象的所有方法时,都会被替换成执行如下的
invoke
方法
public Object invoke(Object proxy, Method method, Object[] args)
throws Exception{
DogUtil du = new DogUtil();
//
执行
DogUtil
对象中的
method1
。
du.method1();
//
以
target
作为主调来执行
method
方法
Object result = method.invoke(target , args);
//
执行
DogUtil
对象中的
method2
。
du.method2();
return result;}}
15.7
反射的应用:动态代理
动态代理与
AOP
(
Aspect Orient Programming)
public class MyProxyFactory{
//
为指定
target
生成动态代理对象
public static Object getProxy(Object target)
throws Exception{
//
创建一个
MyInvokationHandler
对象
MyInvokationHandler handler =
new MyInvokationHandler();
//
为
MyInvokationHandler
设置
target
对象
handler.setTarget(target);
//
创建、并返回一个动态代理对象
return
Proxy.newProxyInstance(target.getClass().getClassLoader()
, target.getClass().getInterfaces() , handler);
}
}
15.7
反射的应用:动态代理
动态代理与
AOP
(
Aspect Orient Programming)
public class Test{
public static void main(String[] args)
throws Exception{
//
创建一个原始的
HuntingDog
对象,作为
target
Dog target = new HuntingDog();
//
以指定的
target
来创建动态代理
Dog dog = (Dog)MyProxyFactory.getProxy(target);
dog.info();
dog.run();
}
}
15.7
反射的应用:动态代理
动态代理与
AOP
(
Aspect Orient Programming)
使用
Proxy
生成一个动态代理时,往往并不会凭空产生一个动态代理,这样没有
太大的意义。通常都是为指定的目标对象生成动态代理
这种动态代理在
AOP
中被称为
AOP
代理,
AOP
代理可代替目标对象,
AOP
代理
包含了目标对象的全部方法。但
AOP
代理中的方法与目标对象的方法存在差异:
AOP
代理里的方法可以在执行目标方法之前、之后插入一些通用处理
动态代理与
AOP (Aspect Orient Programming)
动态代理增加的通用方法
1
回调目标对象的方法
动态代理增加的通用方法
2
代
理
的
方
法
15.7
反射的应用:动态代理
AOP