(一)什么是代理模式
通过引入一个代理对象,来操作、控制、访问真实对象。
给目标对象提供一个代理,并由代理对象控制对目标对象的引用。
(二)静态代理
1)模式结构
2)角色
Subject: 抽象主题角色
RealSubject: 真实主题角色
Proxy: 代理主题角色
3)简化的结构图
代理模式示意结构图比较简单,一般可以简化为如下图所示,但是在现实中要复杂很多。
4)代码示例:
//接口
public interface IUserDao {
void save();
}
//目标对象;真实对象;要被代理的对象
public class UserDao implements IUserDao {
@Override
public void save() {
System.out.println("-----数据已经保存了-----");
}
}
//代理对象,静态代理
public class Proxy implements IUserDao {
//把目标对象作为代理类的属性
private IUserDao target;
//采用聚合的方式,把目标对象通过构造参数传过来
public Proxy(IUserDao target) {
super();
this.target = target;
}
@Override
public void save() {
System.out.println("开始事务...");
target.save();
System.out.println("提交事务...");
}
}
//客户端测试
public class MyTest {
public static void main(String[] args) {
//目标对象
IUserDao target=new UserDao();
//把目标对象通过构造参数传给代理对象
Proxy proxy=new Proxy(target);
proxy.save();
}
}
(三)JDK动态代理
1)代码示例
//接口
public interface UserService {
void add();
}
//目标对象;被代理对象;需要实现接口
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("添加数据");
}
}
//把目标对象传给这个类,并通过这个类的getProxy方法拿到目标对象的代理对象
public class ProxyFactory {
//维护一个目标对象
private Object target;
public ProxyFactory(Object target) {
super();
this.target = target;
}
//创建一个InvocationHandler对象
private InvocationHandler handler=new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before...");
Object result=method.invoke(target, args);
System.out.println("after...");
return result;
}
};
//为目标对象创建代理对象
public Object getProxy(){
return Proxy.newProxyInstance(
target.getClass().getClassLoader(),
target.getClass().getInterfaces(),
handler);
}
}
//客户端测试类
public class MyTest {
public static void main(String[] args) {
//目标对象
UserService service=new UserServiceImpl();
//获取代理对象
//该代理对象一定会实现目标对象的接口UserService,因此可以强转
UserService proxy=(UserService)new ProxyFactory(service).getProxy();
proxy.add();
}
}
注意:在JDK动态代理中,目标对象一定要实现接口,否则不能使用JDK动态代理
(四)cglib动态代理
思考:上面的静态代理和JDK动态代理,都要求目标对象实现某个接口。如果目标对象没有实现任何接口,那该怎么办呢?这时候应该使用cglib动态代理。
1)cglib动态代理,为指定的目标类生成一个子类,并覆盖其中方法实现增强,但因为采用的是继承,所以不能对final修饰的类进行代理。
2)需要引入cglib的jar包,由于Spring的核心包中已经包括了cglib功能,所以直接引入spring-core-4.0.6.RELEASE.jar即可。
3)代码示例
//目标对象,未实现任何接口
public class UserDao {
public void print(){
System.out.println("hello world");
}
}
//把目标对象传给这个类,并且通过这个类获取目标对象的代理对象
public class Cglib implements MethodInterceptor{
//维护目标对象
private Object target;
public Cglib(Object target) {
super();
this.target = target;
}
//为目标对象创建代理对象
public Object getProxy(){
//工具类
Enhancer en=new Enhancer();
//设置父类
en.setSuperclass(target.getClass());
//设置回调函数
en.setCallback(this);
//创建代理对象
return en.create();
}
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable {
System.out.println("开始事务...");
Object result=method.invoke(target, args);
System.out.println("提交事务...");
return result;
}
}
//客户端测试类
public class MyTest {
public static void main(String[] args) {
//目标对象
UserDao dao=new UserDao();
//获取代理对象
//代理类是目标类UserDao的子类,因此可以强转
UserDao proxy=(UserDao)new Cglib(dao).getProxy();
proxy.print();
}
}