设计模式之代理模式
# 设计模式之代理模式
# 一、简介
将一个对象包装起来以控制和管理对对象的访问
# 二、实现方式
# 1、静态代理
代理类需要自己编写代码
我们以找房租房为例,我们一般找中介找房子,这里中介就是代理者。代码示例:
- 租房方法
public interface IRentHouse {
void rentHouse();
}
1
2
3
2
3
- 定义租房的实现类
public class RentHouse implements IRentHouse {
@Override
public void rentHouse() {
System.out.println("租了一间房子。。。");
}
}
1
2
3
4
5
6
2
3
4
5
6
- 代理
public class IntermediaryProxy implements IRentHouse {
private IRentHouse rentHouse;
public IntermediaryProxy(IRentHouse irentHouse){
rentHouse = irentHouse;
}
@Override
public void rentHouse() {
System.out.println("交中介费");
rentHouse.rentHouse();
System.out.println("中介负责维修管理");
}
}
1
2
3
4
5
6
7
8
9
10
11
12
2
3
4
5
6
7
8
9
10
11
12
- 测试类
public static void main(String[] args){
//定义租房
IRentHouse rentHouse = new RentHouse();
//定义中介
IRentHouse intermediary = new IntermediaryProxy(rentHouse);
//中介租房
intermediary.rentHouse();
}
1
2
3
4
5
6
7
8
2
3
4
5
6
7
8
# 2、动态代理
# 2.1、JDK动态代理
主要是利用反射机制生成一个实现代理接口的类。目标对象一定要实现接口,否则不能使用JDK代理
JDK动态代理的实现需要使用java.lang.reflect.Proxy.newProxyInstance
方法,这个方法有三个参数:
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
1
ClassLoader loader
:目标对象使用的类加载器
Class<?>[] interfaces
:目标对象实现的接口的类型,使用泛型方式确认类型
InvocationHandler h
:调用处理器,在执行目标对象的方法时,会触发调用InvocationHandler
类的invoke()
方法,会把当前执行目标对象的方法作为参数传进来
代码示例:
/**
* 代理工厂类:ProxyFactory.java
* 创建动态代理对象
* 动态代理不需要实现接口,但是需要指定接口类型
*/
public class ProxyFactory{
private Object target;//维护一个目标对象
public ProxyFactory(Object target){
this.target=target;
}
public Object getProxyInstance(){//给目标对象生成代理对象
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("开始事务2");
//执行目标对象方法
Object returnValue = method.invoke(target, args);
System.out.println("提交事务2");
return returnValue;
}
}
);
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
public static void main(String[] args) {
IUserDao target = new UserDao();// 目标对象
// 【原始的类型 class cn.itcast.b_dynamic.UserDao】
System.out.println(target.getClass());
// 给目标对象,创建代理对象
IUserDao proxy = (IUserDao) new ProxyFactory(target).getProxyInstance();
// class $Proxy0 内存中动态生成的代理对象
System.out.println(proxy.getClass());
proxy.save(); // 执行方法 【代理对象】
}
1
2
3
4
5
6
7
8
9
10
2
3
4
5
6
7
8
9
10
# 2.2、Cglib动态代理,也叫作子类代理
通过继承目标类,创建它的子类,在子类中重写父类的方法,来实现功能的修改
- 实现方法
1.需要引入cglib
的jar文件,但是在Spring
的核心包中已经包括了Cglib
功能,所以直接引入spring-core-3.2.5.jar
即可.
2.引入功能包后,就可以在内存中动态构建子类
3.目标类不能为final,否则会报错
4.目标类的方法不能为final/static,否则不会被拦截,即不会执行目标对象额外的业务方法.
- 代码示例
/**
* 目标对象,没有实现任何接口
*/
public class UserDao {
public void save() {
System.out.println("----已经保存数据!----");
}
}
1
2
3
4
5
6
7
8
9
2
3
4
5
6
7
8
9
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
/**
* Cglib子类代理工厂
* 对UserDao在内存中动态构建一个子类对象
*/
public class ProxyFactory implements MethodInterceptor {
//维护目标对象
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
//给目标对象创建一个代理对象
public Object getProxyInstance(){
Enhancer en = new Enhancer();//1.工具类
en.setSuperclass(target.getClass());//2.设置父类
en.setCallback(this);//3.设置回调函数
return en.create();//4.创建子类(代理对象)
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("开始事务...");
Object returnValue = method.invoke(target, args);//执行目标对象的方法
System.out.println("提交事务...");
return returnValue;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
# 三、应用场景
# 1、Spring AOP底层实现
在Spring AOP
中,有一个类DefaultAopProxyFactory
,它下面有一个方法createAopProxy()
,里面会判断目标类是否可以表示为接口类型,如果是的话就使用JDK动态代理JdkDynamicAopProxy
,否则就使用Cglib动态代理ObjenesisCglibAopProxy
public class DefaultAopProxyFactory implements AopProxyFactory, Serializable {
@Override
public AopProxy createAopProxy(AdvisedSupport config) throws AopConfigException {
if (!NativeDetector.inNativeImage() &&
(config.isOptimize() || config.isProxyTargetClass() || hasNoUserSuppliedProxyInterfaces(config))) {
Class<?> targetClass = config.getTargetClass();
if (targetClass == null) {
throw new AopConfigException("TargetSource cannot determine target class: " +
"Either an interface or a target is required for proxy creation.");
}
if (targetClass.isInterface() || Proxy.isProxyClass(targetClass)) {
return new JdkDynamicAopProxy(config);
}
return new ObjenesisCglibAopProxy(config);
}
else {
return new JdkDynamicAopProxy(config);
}
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20