一、概述
代理是一种模式,提供了对目标对象的间接访问方式,即通过代理访问目标对象。如此便于在目标实现的基础上增加额外的功能操作,前拦截,后拦截等,以满足自身的业务需求,同时代理模式便于扩展目标对象功能的特点也为多人所用。
按照代理的创建时期,代理类可以分为两种:
静态:由程序员创建代理类或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
动态:在程序运行时运用反射机制动态创建而成。
我们根据加载被代理类的时机不同,将代理分为静态代理和动态代理。如果我们在代码编译时就确定了被代理的类是哪一个,那么就可以直接使用静态代理;如果不能确定,那么可以使用类的动态加载机制(反射),在代码运行期间加载被代理的类这就是动态代理,比如RPC框架和Spring AOP机制。
二、图形描述
三、静态代理
静态代理的实现比较简单,代理类通过实现与目标对象相同的接口,并在类中维护一个代理对象。通过构造器塞入目标对象,赋值给代理对象,进而执行代理对象实现的接口方法,并实现前拦截,后拦截等所需的业务功能,一个典型的代理模式通常有三个角色,这里称之为**代理三要素**:共同的接口,代理对象、被代理对象
package com.bjsxt.staticProxy;
/**
* Created by Administrator on 2019/3/10.
*/
public class TestStaticProxy {
public static void main(String[] args){
//用法类似于线程的代理对象 new Thread(线程对象).start();
new WeddingCompany(new You()).happyMarry();
}
}
/**
* 共同的接口
*/
interface Marry{
void happyMarry();
}
/**
* 真实的角色,被代理角色
*/
class You implements Marry{
@Override
public void happyMarry() {
System.out.println("你结婚了。。。");
}
}
/**
* 代理角色,代理真实的角色
*/
class WeddingCompany implements Marry{
private Marry marry; //代理对象内部维护一个真实的角色(需要代理的角色)
public WeddingCompany(Marry marry){
this.marry=marry;
}
@Override
public void happyMarry() {
ready();
marry.happyMarry();
after();
}
private void ready() {
System.out.println("布置婚礼。。。。");
}
private void after() {
System.out.println("闹洞房。。。。");
}
}
静态代理的总结
优点:可以做到不对目标对象进行修改的前提下,对目标对象进行功能的扩展和拦截。
缺点:因为代理对象,需要实现与目标对象一样的接口,会导致代理类十分繁多,不易维护,同时一旦接口增加方法,则目标对象和代理类都需要维护。
四、动态代理
在上面的示例中,一个代理只能代理一种类型,而且是在编译器就已经确定被代理的对象。而动态代理是在运行时,通过反射机制实现动态代理,并且能够代理各种类型的对象,动态代理有两种方式jdk动态代理和cglib动态代理
(1)使用jdk动态代理
我们看到jdk的代理机制必须要求被代理类实现某个方法,这样在生成代理类的时候才能知道重写那些方法。(事实上jdk动态代理会动态生成一个被代理类所实现的接口的实现类,跟静态代理类似)这样一个没有实现任何接口的类就无法通过jdk的代理机制进行代理,当然解决方法是使用cglib的代理机制进行代理。
package com.bjsxt.dynamicProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.util.Map;
/**
* JDK动态代理:使用前提(基于接口的实现)
* JDK动态代理:本质上生产了一个代理类,该代理与被代理目标实现相同的接口,
* 当前用户访 问代理类中的方法时,将委派InvacationHandler中的invoke()方法进行处理,
* 在invoke()方法中添加业务处理代理和回调被代理目标中方法。
*/
public class TestJdkProxy {
public static void main(String[] args){
You you=new You();//创建被代理类
WeddingCompany weddingCompany=new WeddingCompany(you);
//生成代理类
Marry marry=(Marry)weddingCompany.createProxy();
//通过代理类,调用被代理类的方法
marry.happyMarry();
}
}
/**
* 共同的接口
*/
interface Marry{
void happyMarry();
}
/**
* 真实的角色,被代理角色
*/
class You implements Marry {
@Override
public void happyMarry() {
System.out.println("你结婚了。。。");
}
}
class WeddingCompany implements InvocationHandler {
private Object target; //被代理的对象
public WeddingCompany(Object target){
this.target=target;
}
/**
* 生成代理
* @return
*/
public Object createProxy(){
//获得加载被代理类的 类加载器
ClassLoader loader = target.getClass().getClassLoader();
//指明被代理对象实现的接口
Class<?>[] interfaces = target.getClass().getInterfaces();
//this是当前类的对象,也是代理类,之后想要调用被代理类的方法时,都会委托给这个类的
return Proxy.newProxyInstance(loader, interfaces, this);
}
/**
*
* @param proxy 代理对象
* @param method 原对象被调用的方法
* @param args 方法传递的参数
* @return
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
ready();
Object returnValue=method.invoke(target,args);
after();
return returnValue;
}
private void ready() {
System.out.println("布置婚礼。。。。");
}
private void after() {
System.out.println("闹洞房。。。。");
}
}
jdk动态代理总结
优点:代理对象无需实现接口,免去了编写很多代理类的烦恼,同时接口增加方法也无需再维护目标对象和代理对象,只需在事件处理器中添加对方法的判断即可。
缺点:代理对象不需要实现接口,但是目标对象一定要实现接口,否则无法使用JDK动态代理。
(2)使用cglib动态代理
cglib是通过继承的方式做的动态代理,因此,如果某个类被标记为final,那么它是无法使用cglib做动态代理。cglib会生成的代理类继承当前的被代理类,并在代理类中对代理方法进行强化处理(前置处理、后置处理等),因此被代理类有没有实现接口都是一样的
当然使用cglib需要添加下cglib所需的jar包:cglib-2.2.2.jar,asm-3.3.1.jar,asm-util-3.3.1.jar,ant-1.6.2.jar
package com.bjsxt.dynamicCglibProxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class TestCglibProxy {
public static void main(String[] args){
You you=new You();//创建被代理类
WeddingCompany weddingCompany=new WeddingCompany(you);
//生成代理类
You you1=(You)weddingCompany.createProxy();
//通过代理类,调用被代理类的方法
you1.happyMarry();
}
}
/**
* 真实的角色,被代理角色
*/
class You {
public void happyMarry() {
System.out.println("你结婚了。。。");
}
}
/**
* 动态没生成代理对象
* 实现 MethodInterceptor方法代理接口,创建代理类
* 当访问代理中的方法时,委派给MethodInteceptor中的处理程序(intercept方法)进行出来,
* 在处理程序中添加了业务逻辑和回掉了被代理目标中的方法。
*/
class WeddingCompany implements MethodInterceptor {
private Object target; //被代理的对象
public WeddingCompany(Object target){
this.target=target;
}
/**
* 创建代理对象
* @return
*/
public Object createProxy() {
//创建加强器,用来创建动态代理类
Enhancer enhancer = new Enhancer();
//为加强器指定要代理的类(即:为下面生成的代理类指定父类)
enhancer.setSuperclass(this.target.getClass());
//设置回调:对于代理类上所有方法的调用,都会调用CallBack,而Callback则需要实现intercept()方法进行拦
enhancer.setCallback(this);
// 创建动态代理类对象并返回
return enhancer.create();
}
/**
*
* @param proxy 生成的代理对象
* @param method 被调用的方法
* @param args 方法的入参
* @param methodProxy
* @return
* @throws Throwable
*/
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
ready();
Object value = method.invoke(target, args);//回掉被代理对象中的方法
after();
return value;
}
private void ready() {
System.out.println("布置婚礼。。。。");
}
private void after() {
System.out.println("闹洞房。。。。");
}
}