代理模式(Proxy pattern)——SpringAOP是用代理模式实现的。
定义:代理模式是指为其他对象提供一种代理,以控制对这个对象的访问。代理对象在客户端和目标对象之间起到中介作用
属于结构型设计模式
生活中的代理模式(这些都是动态代理)
- 房产中介
- 快递小哥
- 黄牛党(抢票在卖给需要的人)
代理模式适用场景
- 保护目标对象
- 增强目标对象
代理的通用写法(general)
public interface ISubject {
void request();
}
public class RealSubject implements ISubject{
public void request() {
System.out.println("real service is called.");
}
}
public class Proxy implements ISubject{
private ISubject subject;
public Proxy(ISubject subject){
this.subject = subject;
}
public void request() {
before();
subject.request();
after();
}
public void before(){
System.out.println("called before request().");
}
public void after(){
System.out.println("called after request().");
}
}
静态代理(显式声明被代理对象)
public interface IPerson {
void findLove();
}
public class XiaoMing implements IPerson{
public void findLove() {
System.out.println("要求肤白貌美大长腿");
}
}
public class DaMing implements IPerson{
private XiaoMing xiaoMing;
public DaMing(XiaoMing xiaoMing){
this.xiaoMing = xiaoMing;
}
public void findLove() {
System.out.println("挑选阶段");
xiaoMing.findLove();
System.out.println("热恋开始");
}
}
public class Test {
public static void main(String[] args){
DaMing daMing = new DaMing(new XiaoMing());
daMing.findLove();
}
}
动态代理(jdk用法)
public interface IPerson {
void findLove();
void buyInsure();
}
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JdkMeipo implements InvocationHandler {
private IPerson target;
public IPerson getInstance(IPerson target){
this.target = target;
Class<?> clazz = target.getClass();
return (IPerson) Proxy.newProxyInstance(clazz.getClassLoader(), clazz.getInterfaces(), this);
}
// 不用自己调用,底层内部自动触发
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object result = method.invoke(this.target, args);
after();
return result;
}
private void after() {
System.out.println("开始交往");
}
private void before() {
System.out.println("开始物色");
}
}
public class XiaoMing implements IPerson {
public void findLove() {
System.out.println("小明要求:肤白貌美大长腿");
}
public void buyInsure() {
System.out.println("60万");
}
}
public class Zhaoliu implements IPerson {
public void findLove() {
System.out.println("赵六要求:有车有房学历高");
}
public void buyInsure() {
System.out.println("100万");
}
}
动态代理(cglib)
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibMeipo implements MethodInterceptor {
public Object getInstance(Class<?> calzz){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(calzz);
enhancer.setCallback(this);
return enhancer.create();
}
private void after() {
System.out.println("开始交往");
}
private void before() {
System.out.println("开始物色");
}
// 不用自己调用,底层内部自动触发
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object result = methodProxy.invokeSuper(o,objects);
after();
return result;
}
}
public class ZhangSan {
public void findLove(){
System.out.println("张三要求肤白貌美大长腿");
}
}
public class Test {
public static void main(String[] args){
ZhangSan zhangSan = (ZhangSan) new CglibMeipo().getInstance(ZhangSan.class);
zhangSan.findLove();
}
}
JDK和CGlib代理的比较
CgLib 继承的方式,覆盖父类方法
JDK采用实现的方式,必须要求代理的目标对象一定实现一个接口
思想:都是通过生成字节码,重组成一个新的类
JDK Proxy 对于用户而言,依赖更强,调用也更复杂
CGlib 对目标类没有任何要求
CGlib 效率更高,性能也更高,底层没有用到反射
JDK Proxy 生成逻辑比较简单,执行效率低,每次都要反射
CGlib 有个坑, 目标代理类不能有fianl的 方法,忽略final修饰的方法
代理模式的优点:
- 代理模式能将代理对象与真实对象的目标对象分离
- 一定程度上降低了系统的耦合度,易于扩展。
- 代理可以起到保护目标对象的作用
- 增强目标对象职责
代理模式的缺点:
- 代理模式会造成系统设计中类的数目增加
- 在客户端和目标对象之间增加了一个代理对象,请求处理速度变慢
- 增加了系统的复杂度
Spring中的代理选择原则
- 当Bean有实现接口时,Spring就会用JDK的动态代理
- 当Bean没有实现接口时,Spring选择CGlib。
- spring可以通过配置强制使用CGlib,只需要在Spring的配置文件中加入如下代码
<aop:aspectj-autoproxy proxy-target-class="true"/>