2.2 注解与动态代理
注解
- 是一种代码级别的说明
- 注解是写给计算机看的
- 作用:
- 编译检查:通过代码标志注解,让编译器实现基本的编译检测
- 代码分析
- 编写文档
注解类型
JDK提供的注解
- Deprecated :被修饰方法已经过时,不建议但仍然可以使用,效果为对应方法被
划除 - Override: 重写方法
- SuppressWarnings(value={选项1,选项2}): 关闭警告,被修饰的类或方法如果存在编译警告,将被编译器忽略
- deprecation:忽略过时
- rawtypes:忽略类群安全
- unused:忽略不使用
- unchecked:忽略安全检查,执行了未检查的转换时的警告
- serial:当在可序列化的类上缺少serialVersionUID定义时的警告
- finally:任何finally子句不能正常完成时的警告
- null:忽略空指针
- fallthrough:switch直接通往下一种情况而没有break时的警告
- all:忽略所有
元注解
- 自定义注解需要使用元注解进行修饰才能真正的使用
- 定义:用于修饰注解的注解
- 元注解
-
@Retention:确定被修饰的自定义注解生命周期
- ReteentionPolicy.SOURCE:只能存在源码中,class没有,用途:提供给编译器使用
- ReteentionPolicy.CLASS:运行时内存没有,默认行为,用途:提供给虚拟机使用
- ReteentionPolicy.RUNTIME:存在于源码、字节码、虚拟机,用途:取代xml配置
-
@Target:确定自定义注解的使用位置
- ElementType.TYPE:修饰类、接口
- ElementType.FIELD
- ElementType.METHOD
- ElementType.PARAMTER
- ElementType.TYPE_PARAMTER
- ElementType.CONSTRUCTOR:修饰构造
- ElementType.LOCAL_VARIABLE
- ElementType.PACKAGE
- ElementType.MODULE
- ElementType.TYPE_USE
-
@Documented:使用javaDoc生成api文档时是否包含此注解,默认情况下注解是不会出现在javadoc中的
-
@Inherited:如果父类使用被修饰的注解,子类是否继承
-
jdk7以后添加的注解
- SafeVarargs:忽略任何使用参数为泛型变量的方法或构造函数调用产生的警告
- FunctionalInterface:jdk8后添加,标志一个匿名函数或函数式接口
- Repeatable:jdk8后开始支持,标志某注解可以在同一个声明上使用多次
自定义注解
- 使用关键字@interface
- 和implemented实现接口不同,annotation接口的实现细节都由编译器完成,并且定义的注解不能继承其他的注解或接口
- 定义类
- 定义接口
- 定义枚举
@元注解 @interface MyAnnol{ public|abstract String username() []default "defaultName"] ; } //使用 @MyAnnol( username = ...; ) public class TestAnno{}
- 属性修饰符:默认且只能是public abstract
- 注意
- 注解可以没有属性,有属性用()
- 多个属性用逗号分隔
- 属性名为vale且当前只有一个属性,value可以省略,否则不能省略
- 属性为数组,内容格式为{1,2,3}
- 属性类型为数组,值只有一个时{}可以省略
- 一个对象只能使用一次(同一个)注解,
Annotation架构
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-PasMbagC-1585648435991)(:storage\b1247d0d-115a-4161-9fd2-ccc8bb2433e0\359acde4.png)]
- Annotation
package java.lang.annotation; public interface Annotation { boolean equals(Object obj); int hashCode(); String toString(); Class<? extends Annotation> annotationType(); }
注解解析
- 获取注解上设置的数据
- 使用java.lang.reflect.AnnotatedElement
- 方法
- boolean isAnnotationPresent(Class AnnotationClass):判断是否有注解
- T getAnnotation(class<T> annotationClass):获取指定的注解
- Annotation[] getAnnotaions():获取对象及其从父类上继承的所有的注解
- Annotation[] getDeclaredAnnotaions():获取对象的所有的注解
代理
静态代理
- 创建一个接口
- 然后创建被代理的类实现该接口并实现该接口的抽象方法,
- 创建一个代理类,同时实现这个接口
//接口 public interface HelloInterface{ void sayHello(); } //被代理类 public class hello implements HelloInterface{ @Override public void sayHello(){ op; } } //代理类 public class proxy implements HelloInterface{ private HelloInterface hello = new Hello(); @Override public void sayHello(){ ... hello.sayHello(); ... } } //使用代理类 proxy pr=new proxy(); pr.sayHello();
- 静态代理只能为一个类服务,且事先知道被代理类
动态代理
- 不用手动编写一个代理对象,不需要一一编写与目标对象相同的方法,这个过程,在运行时的内存中动态生成代理对象
Proxy API
newProxyInstance(ClassLoader loader, Class\<?>[] interfaces, InvocationHandler h)
- loader:ClassName.class.getClassLoader()
- interfaces:需要实现的所有类
- 目标类实例.getClass().getInterfaces()(只能获得自己的接口)
- new Class[] {UserService.class}
- h:处理类、接口,必须进行实现类
- 重写invoke(onject proxy,Method method,Object[] args),代理类的每一个方法执行时,都将调用一次invoke
- 参数1:代理对象
- 参数2:代理对象当前执行方法的描述对象
- 执行方法名:method.getName()
- 执行方法:method.invoke(对象,实际参数)
- 参数3:方法实际参数
List<String> proxyInstance = ( List<String>)Proxy.newProxyInstance(list.getClass().getClassLoader(), list.getClass().getInterfaces(), new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return method.invoke(list, args); } }); proxyInstance.add("你好"); System.out.println(list);
- 重写invoke(onject proxy,Method method,Object[] args),代理类的每一个方法执行时,都将调用一次invoke
- 动态代理底层实现
- 通过实现InvocationHandler接口实现自己的调用处理器
- 通过proxy类指定classloader对象和一组接口来创建动态代理类
- 通过反射获得动态代理类的构造函数,其唯一参数类型是调用处理器接口类型
- 通过构造函数创建动态代理类实例