一、基本介绍
核心作用:通过代理,控制对对象的访问,可以详细控制访问某个(某类)对象的方法,在调用这个方法前做前置处理,调用这个方法后做后置处理。
应用场景: 安全代理:屏蔽对真实角色的直接访问。
远程代理:通过代理类处理远程方法调用(RMI)
延迟加载:先加载轻量级的代理对象,真正需要再加载真实对象。(比如你要开发一个大文档查看软件,大文档中有大的图片,有可能一个图片有100MB,在打开文件时不可能将所有的图片都显示出来,这样就可以使用代理模式,当需要查看图片时,用proxy来进行大图片的打开)
代理模式分类:静态代理和动态代理
二、静态代理(需要自己手动生成代理类)
核心角色:抽象角色:定义代理角色和真实角色的公共对外方法
真实角色:实现抽象角色,定义真实角色所要实现的业务逻辑,供代理角色调用,关注真正的业务逻辑!
代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作。将统一的流程控制放到代理角色中处理!
举例:比如对于歌手而言都有自己的经纪人,经纪人就相当于一个代理对象,歌手仅仅负责唱歌,其他的接活、门票价格、演出费等等这些是代理对象去操作
1.首先创建一个接口,接口中定义代理角色和真实角色的公共对外方法
public interface Star {
//面谈
void confer();
//签合同
void signContract();
//订票
void bookTicket();
//唱歌
void sing();
//收钱
void collectMoney();
}
2.定义真实的对象(真实的对象只要完善自己需要做的方法即可,比如说歌手就只需完善sing()方法)
public class RealStar implements Star {
@Override
public void confer() {
System.out.println("");
}
@Override
public void signContract() {
}
@Override
public void sing() {
System.out.println("唱歌");
}
@Override
public void collectMoney() {
}
}
3.定义代理对象 ,对于真实对象需要执行的方法就去调用真是对象
public class ProxyStar implements Star {
private Star realStar;
public ProxyStar(Star star) {
this.realStar = star;
}
@Override
public void confer() {
System.out.println("与邀请方商谈");
}
@Override
public void signContract() {
System.out.println("与邀请方签合同");
}
@Override
public void sing() {
realStar.sing();
}
@Override
public void collectMoney() {
System.out.println("收钱");
}
}
4.测试
public class Client {
public static void main(String[] args) {
Star realStar = new RealStar();
Star proxy = new ProxyStar(realStar);
proxy.confer();
proxy.signContract();
proxy.sing();
proxy.collectMoney();
}
}
静态代理比较简单,一般常用的是动态代理,接下来研究以下动态代理模式。
三、动态代理(程序动态生成代理类)
动态代理的实现有多种这里介绍常用的两种:JDK动态代理和CGLIB动态代理
1.JDK动态代理(必须有接口类)
是java.lang.reflect.*包提供的方式,它必须借助一个接口才能产生代理对象,所以需要先定义接口
public interface HelloWorld {
public void sayHelloWorld();
}
创建一个实现类
public class HelloWorldImpl implements HelloWorld {
@Override
public void sayHelloWorld() {
System.out.println("Hello,World!");
}
}
在JDK动态代理中,要实现代理类就必须先有一个类要实现java.lang.reflect.InvocationHandler接口,它里面定义了一个invoke方法,并提供接口数组用于下挂代理对象
下面的JDKProxyExample可以接收任意的对象并为其生成代理对象
public class JDKProxyExample implements InvocationHandler {
private Object target = null;
public JDKProxyExample(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("进入代理逻辑方法");
Object obj = method.invoke(target, args);
System.out.println("在调度完真实对象后");
return obj;
}
}
生成代理类并运行真实对象的方法
Proxy.newProxyInstance()方法用来生成代理对象,其中包含三个参数。
参数1:需要传入一个类加载器,直接传入java系统的类加载器即可
参数2:把生成的动态代理对象下挂在那个接口下,所以需要传递真实对象实现的接口类
参数3: 传递实现了java.lang.reflect.InvocationHandler的类
public class testJDkProxy {
public static void main(String[] args) {
HelloWorld helloWorld = new HelloWorldImpl();
JDKProxyExample jdkProxyExample = new JDKProxyExample(helloWorld);
HelloWorld handler = (HelloWorld) Proxy.newProxyInstance(ClassLoader.getSystemClassLoader(),
helloWorld.getClass().getInterfaces(), jdkProxyExample);
handler.sayHelloWorld();
}
}
2.CGLIB动态代理
JDK动态代理必须提供接口才可以使用,在一些不能提供接口的环境中,只能采用其他的第三方技术,比如CGLIB,它的又是在于不需要提供接口,只要一个非抽象类就能实现动态代理。
由于cglib是第三方技术,所以需要添加其jar包,下面的代码是cglib的Maven坐标
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>
首先定义真实对象类
public class HelloWorld {
public void say(){
System.out.println("Hello,World");
}
}
Enhancer可能是CGLIB中最常用的一个类,Enhancer既能够代理普通的class,也能够代理接口。这里Enhancer通过设置传递进来cls为超类,然后通过setCallback方法设置那个类为该超类即传递进来的cls类的代理类(setCallback中设置的类必须实现intercept方法),最后返回代理对象
public class CglibProxyExample implements MethodInterceptor {
//生成cglib动态代理对象,需传递真实对象的class
public Object getProxy(Class cls){
//CGLIB enchancer增强类对象
Enhancer enhancer = new Enhancer();
//设置增强类型
enhancer.setSuperclass(cls);
//定义代理逻辑对象为当前对象,要求当前对象实现MethodInterceptor方法
enhancer.setCallback(this);
//生成并返回代理对象
return enhancer.create();
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("调用真实对象前");
Object result = methodProxy.invokeSuper(proxy, args);
System.out.println("调用真实对象后");
return result;
}
}
测试类:
public class test {
public static void main(String[] args) {
CglibProxyExample cglibProxyExample = new CglibProxyExample();
HelloWorld proxy = (HelloWorld) cglibProxyExample.getProxy(HelloWorld.class);
proxy.say();
}
}