动态代理机制简单使用

张天宇 on 2020-07-10

动态代理的使用。

概述

代理 (Proxy) 是一种设计模式,提供了对目标对象另外的访问方式;即通过代理对象访问目标对象.这样做的好处是:可以在目标对象实现的基础上,增强额外的功能操作,即扩展目标对象的功能。这里使用到编程中的一个思想:不要随意去修改别人已经写好的代码或者方法,如果需改修改,可以通过代理的方式来扩展该方法。

静态代理

这里使用明星与经纪人的关系来举个例子:很多明星出名之后,通告太多,邀请他的公司呢希望能一次性把费用和节目谈好,但是明星显然做不来这么多事情。于是经纪公司就对一人进行包装配备经纪人。从而形成一整套方案,这样满足甲方就非常方便了。

Java 中的静态代理类似于装饰者模式,静态代理在使用时,需要定义接口或者父类,被代理对象与代理对象一起实现相同的接口或者是继承相同父类。

1
2
3
public interface People {
public void sing(String song);
}
1
2
3
4
5
6
7
@Slf4j
public class Star implements People {
@Override
public void sing(String song) {
log.debug("啊~" + song + "~~");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
@Slf4j
public class StarProxy implements People {
private People people;
public StarProxy(People people) {
this.people = people;
}
@Override
public void sing(String song) {
log.debug("接洽会谈");
people.sing("忘情水");
log.debug("收工打钱");
}
}
1
2
3
People dehua = new Star();
StarProxy starProxy = new StarProxy(dehua);
starProxy.sing("忘情水");

动态代理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@Slf4j
public class StarFactory implements InvocationHandler{
private People people;
public StarFactory(People people) {
this.people = people;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.debug("商务洽谈");
Object o = method.invoke(people, args);
log.debug("收工打钱");
return o;
}
public Object getInstance() {
return Proxy.newProxyInstance(people.getClass().getClassLoader(), people.getClass().getInterfaces(), this});
}
}
1
2
3
People dehua = new Star();
People jjr = (People) new StarFactory(dehua).getInstance();
jjr.sing("忘情水");
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
@Slf4j
public class StarFactory {
private People people;
public StarFactory(People people) {
this.people = people;
}
public Object getInstance() {
return Proxy.newProxyInstance(people.getClass().getClassLoader(), people.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log.debug("商务洽谈");
Object object = method.invoke(people, args);
log.debug("收工打钱");
return object;
}
});
}
}
1
2
3
People dehua = new Star();
People jjr = (People) new StarFactory(dehua).getInstance();
jjr.sing("忘情水");

CGLIB 动态代理

依赖

1
2
3
4
5
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>2.1_3</version>
</dependency>

代理类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@Slf4j
public class StarFactory2 implements MethodInterceptor {
public Object getInstance(Class clazz) {
Enhancer en = new Enhancer();//帮我们生成代理对象
en.setSuperclass(clazz);//设置对谁进行代理
en.setCallback(this);//代理要做什么
return en.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
log.debug("商务洽谈");
Object returnValue = methodProxy.invokeSuper(o, objects);
log.debug("收工打钱");
return returnValue;
}
}
1
2
3
People dehua = new Star();
Star jjr = (Star) new StarFactory2().getInstance(Star.class); // 无需使用接口类
jjr.sing("忘情水");

原理参考

https://www.jianshu.com/p/9a61af393e41

https://www.jianshu.com/p/471c80a7e831

Java 反射

反射 API 用来生成 JVM 中的类、接口或则对象的信息。

API

  1. Class 类:反射的核心类,可以获取类的属性,方法等信息。
  2. Field 类:Java.lang.reflec 包中的类,表示类的成员变量,可以用来获取和设置类之中的属性
    值。
  3. Method 类: Java.lang.reflec 包中的类,表示类的方法,它可以用来获取类中的方法信息或
    者执行方法。
  4. Constructor 类: Java.lang.reflec 包中的类,表示类的构造方法。

反射步骤

获取 Class 对象,调用对象方法。

  1. 获取想要操作的类的 Class 对象,他是反射的核心,通过 Class 对象可以任意调用类的方法。
  2. 调用 Class 类的方法,即反射的使用阶段
  3. 使用反射 API 来操作这些信息

获取 Class 对象的三种方法

  1. 调用某对象的 getClass() 方法

    1
    2
    Person p = new Person();
    Class clazz = p.getClass();
  2. 调用某个类的 class 属性获取该类对应的 Class 对象

    1
    Class clazz = Person.class;
  3. 使用 Class 类中的 forName() 静态方法,最安全,性能最好

    1
    Class clazz = Class.forName("类的全路径");

获得了类对象之后,可以通过 Class 类中的方法获取并查看该类中的方法和属性:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Class clazz = Class.forName("reflection.Person");
// 获取 Person 类的所有方法信息
Method[] method = clazz.getDeclaredMethod();
for (Method m: method){
System.out.println(m.toString());
}
// 获取Person 类的所有成员属性信息
Field[] field = clazz.getDeclaredFields();
for (Field f: field){
System.out.println(f.toString);
}
// 获取 Person 类的所有构造方法信息
Constructor[] constructor = clazz.getDeclaredConstructors();
for (Constructor c: constructor){
System.out.println(c.toString());
}

创建对象的两种方法

  1. Class 对象的 newInstance()

    使用 Class 对象的 newInstance()方法来创建该 Class 对象对应类的实例,但是这种方法要求该 Class 对象对应的类有默认的空构造器。

  2. Constructor 对象的 newInstance()

    先使用 Class 对象获取指定的 Constructor 对象,再调用 Constructor 对象的 newInstance()方法来创建 Clas 对象对应类的实例,通过这种方法可以选定构造方法创建实例。

    1
    2
    3
    4
    5
    6
    7
    // 获取 Person 类的 Class 对象
    Class clazz = Class.forName("reflection.Person");
    // 使用 newInstance 方法创建对象
    Person = (Person) clazz.newInstance();
    // 获取构造方法并创建对象
    Constructor c = clazz.getDeclaredConstructor(String.class, String.class, int.class);
    Person p1 = (Person) c.newInstance("张三", "男", 20);