(3)程序可以调用 AnnotationElement 对象的如下方法来访问 Annotation 信息
26、动态代理
(1)明确两个概念:
代理对象存在的价值:主要用于拦截对真实业务对象的访问。
代理对象有什么方法?
(2)现在要生成某一个对象的代理对象,这个代理对象通常也要编写一个类来生成,所以首先要编写用于生成代理对象的类。
(3)如何编写生成代理对象的类,两个要素:
代理谁
如何生成代理对象
(4)代理谁?
设计一个类变量,以及一个构造函数,记住代理类 代理哪个对象。
(5)如何生成代理对象?
设计一个方法生成代理对象(在方法内编写代码生成代理对象是此处编程的难点)
(6)Java提供了一个Proxy类,调用它的newInstance方法可以生成某个对象的代理对象,使用该方法生成代理对象时,需要三个参数:
1.生成代理对象使用哪个类装载器
2.生成哪个对象的代理对象,通过接口指定
3.生成的代理对象的方法里干什么事,由开发人员编写handler接口的实现来指定。
(7)初学者必须理解,或不理解必须记住的2件事情:
Proxy类负责创建代理对象时,如果指定了handler(处理器),那么不管用户调用代理对象的什么方法,该方法都是调用处理器的invoke方法。
由于invoke方法被调用需要三个参数:代理对象、方法、方法的参数,因此不管代理对象哪个方法调用处理器的invoke方法,都必须把自己所在的对象、自己(调用invoke方法的方法)、方法的参数传递进来。
package com.itheima.proxy;
public class SpringBrother implements Human {
public void sing(float money) {
System.out.println("拿到"+money+"钱,开唱");
}
public void dance(float money) {
System.out.println("拿到"+money+"钱,开跳");
}
public void eat() {
System.out.println("吃饭");
}
}
package com.itheima.proxy;
public interface Human {
void sing(float money);
void dance(float money);
void eat();
}
package com.itheima.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class Client {
public static void main(String[] args) {
final Human h = new SpringBrother();
//动态得到代理人
/**
* loader:代理人使用的类加载器。与被代理人h使用的是一样的
* interfaces:代理人要实现的接口。与被代理人h所实现的接口是一样的
* InvocationHandler h:策略设计模式。具体该怎么代理?
*/
Human proxyHuman = (Human)Proxy.newProxyInstance(h.getClass().getClassLoader(), h.getClass().getInterfaces(), new InvocationHandler() {
//具体怎么代理:具体代理策略
/**
* 调用被代理人的任何方法都会执行该方法
* proxy:代理对象的引用
* method:当前执行的是什么方法
* args:当前执行的方法需要的参数
*/
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// System.out.println("被代理了");
if("sing".equals(method.getName())){
//判断出场费
float money = (Float)args[0];
if(money>=10000){
return method.invoke(h, money/2);
}
return null;
}else if("dance".equals(method.getName())){
//判断出场费
float money = (Float)args[0];
if(money>=20000){
return method.invoke(h, money/2);
}
return null;
}else{
return method.invoke(h, args);
}
}
});
proxyHuman.sing(20000);
proxyHuman.dance(30000);
proxyHuman.eat();
}
}
27、动态代理应用
(1)在动态代理技术里,由于不管用户调用代理对象的什么方法,都是调用开发人员编写的处理器的invoke方法(这相当于invoke方法拦截到了代理对象的方法调用)。
(2)并且,开发人员通过invoke方法的参数,还可以在拦截的同时,知道用户调用的是什么方法,因此利用这两个特性,就可以实现一些特殊需求,例如:拦截用户的访问请求,以检查用户是否有访问权限、动态为某个对象添加额外的功能。
28、类加载器
(1)类加载器负责将 .class 文件(可能在磁盘上, 也可能在网络上) 加载到内存中, 并为之生成对应的 java.lang.Class 对象
(2)当 JVM 启动时,会形成由三个类加载器组成的初始类加载器层次结构:
29、bootstrap classloader
(1)bootstrap classloader:引导(也称为原始)类加载器,它负责加载Java的核心类。这个加载器的是非常特殊的,它实际上不是 java.lang.ClassLoader的子类,而是由JVM自身实现的。可以通过执行以下代码来获得bootstrap classloader加载了那些核心类库:
因为JVM在启动的时候就自动加载它们,所以不需要在系统属性CLASSPATH中指定这些类库
30、extension classloader
extension classloader -扩展类加载器,它负责加载JRE的扩展目录(JAVA_HOME/jre/lib/ext或者由java.ext.dirs系统属性指定的)中的JAR包。这为引入除Java核心类以外的新功能提供了一个标准机制。因为默认的扩展目录对所有从同一个JRE中启动的JVM都是通用的,所以放入这个目录的 JAR类包对所有的JVM和system classloader都是可见的。
31、system classloader
(1)system classloader - 系统(也称为应用)类加载器,它负责在JVM被启动时,加载来自在