目录
一、静态代理
先看示例
/**
* 签字类
* @author HX
*
*/
public interface Sign {
/**
* 签字接口方法
*/
void sign();
}
/**
* -老板
* @author HX
*
*/
public class Boss implements Sign {
@Override
public void sign() {
System.out.println("我是老板,我要签字了!");
}
}
/**
* - 这是代理类,秘书
* @author HX
*
*/
public class SecretaireProxy implements Sign {
private Boss boss;
public SecretaireProxy(Boss boss) {
this.boss = boss;
}
@Override
public void sign() {
System.out.println("老板签字前,秘书先检查");
boss.sign();
System.out.println("老板签字后,秘书再作其它处理");
}
}
/**
* -一个员工要让老板签字,交到秘书处
* @author HX
*
*/
public class Client {
public static void main(String[] args) {
// 员工想找老板签字,但其级别不能面老板,只能将签字文件交给老板秘书,
// 告诉秘书这是需要老板签字的文件(代理 前处理)
Boss boss = new Boss();
// 老板秘书将文件进行分类整理,将不需要老板签字的文件处理掉,
// 将需要老板签字的文件交给老板签字(执行签字方法,告诉老板签字了)
SecretaireProxy secretaireProxy = new SecretaireProxy(boss);
// 老板签字完成,秘书取回文件,然后将文件进行分类(按部门或其它),通知文件员工取回文件(代理 后处理)
secretaireProxy.sign();
}
}
result:
老板签字前,秘书先检查
我是老板,我要签字了!
老板签字后,秘书再作其它处理
原理
Sign接口存在的作用:
让目标对象和代理类实现同一个接口,目的是让客户端访问的时候行为一致
Proxy:代理对象,通常具有以下功能
- 实现与具体目标对象一样的接口,这样主要可以使代理类与目标类行为一致。(老板和秘书行为一致)
- 保存一个具体的目标对象引用,可以在需要的时候调用具体的目标对象的方法。
- 可以控制对具体目标对象的访问
特点
-
优点:
可以在不修改目标对象的前提下,对目标对象的功能进行扩展(老板只关注签字,其余处理都交给秘书处理)
-
缺点:
- 代理对象Proxy对象和目标对象寅相同的接口,有一个目标对象就要有一个代理对象,这样会产生许多代理类,臃余太大
- 一旦接口增加方法,其实现类(老板和秘书)都要去维护,代价太大
二、动态代理(JDK代理)
基于静态代理的缺点,出现了动态代理
特点:
- 不需要自己写代理对象,但是目标对象还是实现接口
- 代理对象的生成,是利用JDK API,动态的在内存中构建代理对象
- 动态代理也叫JDK代理,接口代理
JDK中生成代理对象的API:
Proxy java.lang.reflect.Proxy
static Object newProxyInstance(
ClassLoader loader, // 指定当前目标对象使用类加载器
Class<?>[] interfaces, // 目标对象实现的接口的类型
InvocationHandler h // 事件处理器
)
示例来了
/**
* 签字类
* @author HX
*
*/
public interface Sign {
/**
* 签字接口方法
*/
void sign();
}
/**
* -老板
* @author HX
*
*/
public class Boss implements Sign {
@Override
public void sign() {
System.out.println("我是老板,我要签字了!");
}
}
代理工厂:这个工厂可以重复使用,只要传入如老板类一样的类
public class ProxyFactory {
/**
*
* @param target 目标对象(就如老板一般的类)
* @return 返回代理对象(如秘书类)
*/
public static Object getProxyInstance(Object target) {
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("前处理");
Object returnValue = method.invoke(target, args);
System.out.println("后处理");
return returnValue;
}
});
}
}
员工
/**
* -一个员工要让老板签字,交到秘书处
* @author HX
*
*/
public class Client {
public static void main(String[] args) {
// 我要找老板签字
Sign target = new Boss();
// 从秘书办公室找个秘书(ProxyFactory)
Sign proxy = (Sign)ProxyFactory.getProxyInstance(target);
// 老板
proxy.sign();
}
}
result
前处理
我是老板,我要签字了!
后处理
特点
优点:
代理对象不需要实现接口,代理对象也不需要自己创建
缺点:
目标对象一定要实现接口,否则不能用动态代理
三、扩展
CGlib代理:
也叫作子类代理。在内存中构建一个子类对象,从而实现对目标功能的扩展
JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果不想实现接口,就可以使用CGLIB实现。
CGLIB代理要求:⭐目标对象不能为final⭐,否则报错(原理是,CGLIB是通过目标对象的子类创建代理,如果目标对象为final,那就不允许被继承了,就不能使用CGLIB动态代理了)
四、应用
- 拦截器
- 过滤器
- AOP