代理模式和注解

代理模式和注解

1.代理模式

代理模式的概念:

即Proxy Pattern,23种常用的面向对象软件的设计模式之一

代理模式的定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

代理模式的组成:

抽象角色:通过接口或抽象类声明真实角色实现的业务方法。

代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。

真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用。

1.1 静态代理

是由程序员创建或工具生成代理类的源码,再编译代理类。所谓静态也就是在程序运行前就已经存在代理类的字节码文件,代理类和委托类的关系在运行前就确定了。

抽象角色:

1
2
3
4
public interface Itarget {
//抽象方法
public void show ();
}

真实对象:为真正的方法执行者

1
2
3
4
5
6
7
public class Target implements Itarget {
//重写抽象对象中的方法
@Override
public void show() {
System.out.println("show...");
}
}

代理对象:

1
2
3
4
5
6
7
8
9
10
11
12
public class Proxy implements Itarget{
Itarget target;
//构造方法中传入真实对象
public Proxy(Itarget target){
this.target = target;
}
@Override
public void show() {
//实际执行的是真实对象的方法,
target.show();
}
}

客户端通过代理对象执行真实对象的方法:

1
2
3
4
5
6
7
8
9
10
11
public class proxyTest {
@Test
public void test1(){
//创建真实对象
Target target = new Target();
//将真实对象传入代理对象构造方法
Proxy proxy = new Proxy(target);
//调用代理对象的实现方法,实际执行的是真实对象的方法
proxy.show();
}
}

1.2动态代理

是在实现阶段不用关心代理类,而在运行阶段才指定哪一个对象。

动态代理可以不用创建代理对象类,通过proxy.

抽象对象,真实对象同静态代理

客户端通过代理对象执行真实对象的方法:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class targetTest {
@Test
public void test1 (){
//创建真实对象
myProxy target = new target();
//创建代理对象
myProxy proxy = (myProxy) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
//通过匿名内部类的方法
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
return method.invoke(target, args);
}
});
proxy.show();
}
}

1.3 优点

(1).职责清晰

真实的角色就是实现实际的业务逻辑,不用关心其他非本职责的事务,通过后期的代理完成一件完成事务,附带的结果就是编程简洁清晰。

(2).代理对象可以在客户端和目标对象之间起到中介的作用,这样起到了中介的作用和保护了目标对象的作用。

(3).高扩展性

1.4 Java中动态代理

在jdk的api中提供了java.lang.reflect.Proxy它可以帮助我们完成动态代理创建

注意:在java中使用Proxy来完成动态代理对象的创建,只能为目标实现了接口的类创建代理对象。

动态代理是在内存中直接生成代理对象。

img

通过这个方法可以直接创建一个代理对象。

前两个参数帮助我们生产一个代理对象;

第三个参数控制目标行为访问的问题

img

InvocationHandler详解

它是一个接口,接口中声明了一个方法

img

Invoke方法,它是在代理对象调用行为时,会执行的方法,而invoke方法上有三个参数

img

这个方法的主要作用是,当我们通过代理对象调用行为时,来控制目标行为是否可以被调用。

img

在开发中,我们使用动态代理可以完成性能监控,权限控制,日志记录等操作


2.注解Annotation

注解概述

注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以用于创建文档,跟踪代码中的依赖性,甚至执行基本编译时检查。注解是以‘@注解名’在代码中存在的

它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

你可以在编译时选择代码里的注解是否只存在于源代码级,或者它也能在class文件、或者运行时中出现(SOURCE/CLASS/RUNTIME)。

注解作用

如果要对于元数据的作用进行分类,还没有明确的定义,不过我们可以根据它所起的作用,大致可分为三类:

编写文档:通过代码里标识的元数据生成文档。

代码分析:通过代码里标识的元数据对代码进行分析。

编译检查:通过代码里标识的元数据让编译器能实现基本的编译检查

在现在开发中使用注解,一般是用于将注解替换配置文件。(Xml配置文件)

2.1 Java中基本内置注解

  • @override

它的作用是对覆盖超类中方法的方法进行标记,如果被标记的方法并没有实际覆盖超类中的方法,则编译器会发出错误警告。

注意事项:

​ 对于接口中的方法重写,在jdk1.5时@Override它是会报错.

​ 在jdk1.6后的版本就可以描述接口与类之间的重写

  • @Deprecated

它的作用是对不应该再使用的方法添加注解,当编程人员使用这些方法时,将会在编译时显示提示信息

问题:什么时候方法是过时的?

当前版本中方法它存在隐患,在后续版本中对其进行了补充,这时前一个版本中的方法就会标注成过时的。

  • @SuppressWarnings

它的作用是去掉程序中的警告.

其参数有:

deprecation,使用了过时的类或方法时的警告

unchecked,执行了未检查的转换时的警告

fallthrough,当 switch 程序块直接通往下一种情况而没有 break 时的警告

path,在类路径、源文件路径等中有不存在的路径时的警告

serial,当在可序列化的类上缺少serialVersionUID 定义时的警告

finally ,任何 finally 子句不能正常完成时的警告

all,关于以上所有情况的警告

2.2 自定义注解

  • 注解声明:

要声明一个注解通过 @interface

声明一个注解格式 @interface 注解名{}

  • 注解本质分析

分析一下注解的本质:将其.class文件找到,反编译. 可以使用javap命令或反编译工具。

@interface MyAnnoation{}

反编译后的结果

interface MyAnnotation extends Annotation

{

}

结论:注解本质上就是一个接口。它扩展了java.lang.annotation.Annotation接口;

在java中所有注解都是Annotation接口的子接口。

  • 注解成员

注解本质上就是一个接口,那么它也可以有属性和方法。

但是接口中的属性是 public static final的,在注解中注解没有什么意义。

在开发中注解中经常存在的是方法。而在注解中叫做注解的属性.

  • 注解属性类型

    1.基本类型 byte short int long float double char boolean

    2.String

    3.枚举类型

    4.注解类型

    5.Class类型

    6.以上类型的一维数组类型

  • 注解属性的使用

    如果一个注解有属性,那么在使用注解时,要对属性进行赋值操作.

    也可以给属性赋默认值 double d() default 1.23;

    如果属性是数组类型

    ​ 1.可以直接使用 属性名={值1,值2,。。。}方式,例如

    ​ @MyAnnotation(st = “aaa”,i=10,sts={“a”,”b”})

    ​ 2.如果数组的值只有一个也可以写成下面方式

    ​ @MyAnnotation(st = “aaa”,i=10,sts=”a”)

    ​ 注意sts属性它是数组类型,也就是说,只有一个值时,可以省略”{}”

    对于属性名称 value的操作.

    ​ 1.如果属性名称叫value,那么在使用时,可以省略属性名称

    ​ @MyAnnotation(“hello”)

    ​ 2.如果有多个属性,都需要赋值,其中一个叫value,这时,必须写属性名称

    ​ @MyAnnotation(value=”hello”,i=10)

  • 自定义注解-元注解

    什么是元注解及其作用?

    用于修饰注解的注解,可以描述注解在什么范围及在什么阶段使用等

  • 四个元注解介绍

    • @Retention

      指定注解信息在哪个阶段存在 Source Class Runtime

    img

    SOURCE它对应着编译阶段,可以帮助我们进行检查。

    CLASS 它对应解析执行阶段

    RUNTIME

    它对应着在JVM中

  • @Target

    指定注解修饰目标对象类型 TYPE 类、接口 FIELD 成员变量 METHOD 方法

    img

  • Documented

    使用该元注解修饰,该注解的信息可以生成到javadoc 文档中

  • Inherited

    如果一个注解使用该元注解修饰,应用注解目标类的子类会自动继承该注解

@Retention @Target 是自定义注解必须使用两个元注解,并且,@Retention它的值应该是RUNTIME,因为我们会结合反射技术来使用。 @Target我们一般使用TYPE或METHOD