代理模式
定义
目的
静态代理
特点
案例
缺点
动态代理
特点
动态代理的方式
jdk实现方式
jdk动态代理生成对象的步骤
案例
Cglib代理调用
案例
Cglib和jdk动态代理对比
代理模式与Spring
代理模式在Spring源码中的应用
定义
为其他对象提供一种代理,以控制对这个对象的访问。
代理对象在客户端和目标对象之间起到中介作用。
代理模式属于结构型设计模式,分为静态代理和动态代理
目的
保护目标对象
增强目标对象
静态代理
特点
程序运行前代理类的.class文件就已经存在
装饰者模式就是静态代理的一种体现。
案例
被代理对象
package test23;
/**
* 人有很多行为,比如谈恋爱
*/
public interface Person {
void findLove();
}
package test23;
public class Son implements Person {
@Override
public void findLove() {
System.out.println("儿子要求:肤白貌美");
}
}
代理对象
package test23;
/**
* 父亲要帮儿子相亲
*/
public class Father {
private Son son;
public Father(Son son) {
this.son = son;
}
public void findLove(){
System.out.println("父亲物色对象");
son.findLove();
System.out.println("双方同意交往");
}
}
测试类
package test23;
public class Main {
public static void main(String[] args) {
Father father = new Father(new Son());
father.findLove();
}
}
运行结果如下

缺点
大量的代码重复。静态代理类和目标类实现了相同的接口,代理类通过目标类实现了相同的方法。如果接口增加一个方法,除了所有实现类需要实现这个方法外,所有代理类也需要实现此方法。增加了代码维护的复杂度。
静态代理对象只服务于一种类型的对象。如果要服务多类型的对象。势必要为每一种对象都进行代理,静态代理在程序规模稍大时就无法胜任了。
动态代理
动态代理和静态代理的基本思路一致,只不过动态代理功能更加强大,随着业务的扩展适应性更强。
特点
字节码随用随创建,随用随加载。
动态代理的方式
基于接口JDK代理
提供者:JDK 官方的 Proxy 类。
要求:被代理类最少实现一个接口。基于子类CGLIB代理
提供者:第三方的 CGLib,如果报 asmxxxx 异常,需要导入 asm.jar。
要求:被代理类不能用 final 修饰的类(最终类)。
jdk实现方式
jdk动态代理生成对象的步骤
1.获取被代理对象的引用,并且获取它的所有接口,反射获取
2.jdk动态代理类重新生成一个新的类,同时新的类要实现被代理类实现的所有接口
3.动态生成Java代码,新加的业务逻辑方法由一定的逻辑代码调用。
4.编译新生成的Java代码.class文件
5.重新加载到JVM中运行。
案例
package test24;
/**
* 人有很多行为,比如谈恋爱
*/
public interface Person {
void findLove();
}
被代理对象(目标对象)
package test24;
public class Customer implements Person {
@Override
public void findLove() {
System.out.println("高富帅");
}
}
代理对象
package test24;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class JDKMeipo implements InvocationHandler {
//被代理的对象,把引用保存下来
private Object target;
public Object getInstance(Object target) {
this.target = target;
Class<?> clazz = target.getClass();
return Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
before();
Object obj = method.invoke(this.target,args);
after();
return obj;
}
private void before() {
System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
System.out.println("开始物色");
}
private void after() {
System.out.println("如果合适的话,就准备办事");
}
}
测试类
package test24;
public class Main {
public static void main(String[] args) {
try {
Person obj = (Person)new JDKMeipo().getInstance(new Customer());
obj.findLove();
}catch (Exception e){
e.printStackTrace();
}
}
}
运行结果如下

Cglib代理调用
案例
maven项目引入以下依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.2.5</version>
</dependency>
package test25;
/**
* 人有很多行为,比如谈恋爱
*/
public interface Person {
void findLove();
}
被代理对象(目标对象)
package test25;
public class Customer implements Person {
@Override
public void findLove() {
System.out.println("高富帅");
}
}
代理对象
package test25;
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<?> clazz) throws Exception{
Enhancer enhancer = new Enhancer();
//要把那个设置为即将生成的新类的父类
enhancer.setSuperclass(clazz);
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
before();
Object obj = methodProxy.invokeSuper(o,objects);
after();
return obj;
}
private void before() {
System.out.println("我是媒婆,我要给你找对象,现在已经确认你的需求");
System.out.println("开始物色");
}
private void after() {
System.out.println("如果合适的话,就准备办事");
}
}
测试类
package test25;
public class CglibTest {
public static void main(String[] args) {
try{
Customer obj = (Customer) new CglibMeipo().getInstance(Customer.class);
obj.findLove();
}catch (Exception e){
e.printStackTrace();
}
}
}
运行结果如下

Cglib和jdk动态代理对比
jdk动态代理实现了被代理对象的接口,Cglib代理继承了被代理对象。
jdk动态代理和Cglib代理在运行期生成字节码,jdk动态代理直接写Class字节码,Cglib代理使用asm框架写Class字节码,Cglib代理实现更复杂,生成代理类比jdk动态代理效率低。
jdk的动态代理调用代理方法是通过反射机制调用的,Cglib代理是通过FastClass机制直接调用的,Cglib代理的执行效率更高。
代理模式与Spring
代理模式在Spring源码中的应用
ProxyFactoryBean核心方法getObject(),源码如下:
/**
* Return a proxy. Invoked when clients obtain beans from this factory bean.
* Create an instance of the AOP proxy to be returned by this factory.
* The instance will be cached for a singleton, and create on each call to
* {@code getObject()} for a proxy.
* @return a fresh AOP proxy reflecting the current state of this factory
*/
@Override
public Object getObject() throws BeansException {
initializeAdvisorChain();
if (isSingleton()) {
return getSingletonInstance();
}
else {
if (this.targetName == null) {
logger.warn("Using non-singleton proxies with singleton targets is often undesirable. " +
"Enable prototype proxies by setting the 'targetName' property.");
}
return newPrototypeInstance();
}
}





