代理模式
1、通过代理对象访问目标对象,可在目标对象实现的基础上,增加额外的功能操作
2、被代理的对象是远程对象、创建开销大或需要安全控制的对象
3、三种不同形式
- 静态代理
- 动态代理(JDK代理、接口代理)
- Cglib代理(内存动态创建对象,无需实现接口)
静态代理
接口
public interface ITeacherDao {
public void study();
}
目标对象(被代理对象)
public class TeacherDao implements ITeacherDao {
@Override
public void Teach() {
System.out.println("我开始学习了!");
}
}
代理类(Proxy)
public class TeacherDaoProxy implements ITeacherDao {
TeacherDao target;
public TeacherDaoProxy(TeacherDao target) {
this.target = target;
}
@Override
public void Teach() {
System.out.println("吃鸡蛋!");
target.Teach();
System.out.println("吃米饭");
}
}
实现
public class Client {
public static void main(String[] args) {
ITeacherDao proxy = new TeacherDaoProxy(new TeacherDao());
proxy.study();
}
}
结果
缺点
1、目标对象与代理对象必须同时实现相同接口
2、每次接口方法更新,代理对象和目标对象都要更新
3、代理对象需要传入指定目标对象
动态代理
特点:
1、目标对象(被代理类)需要实现接口方法,代理对象无需实现接口
2、代理对象使用Object类型来接收传入的对象
3、代理对象使用java.lang.reflect
包下的Proxy
类的newProxyInstance()
方法来返回目标对象的代理对象
4、无需在代理对象中创建目标对象,而是动态的在内存中创建目标对象的代理对象
newProxyInstance()
参数说明:
public static studyDao newProxyInstance(ClassLoader loader,
Class<?>[] interfaces,
InvocationHandler h)
-
ClassLoader loader:目标对象的类加载器
-
Class<?>[] interface:目标对象实现的所有接口方法,用泛型来接收
-
InvocationHandler h:事件处理,当目标对象执行时会触发事件处理器,会将目标对象以参数形式传入处理
-
new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { Object invoke = method.invoke(target, args); return invoke; }
- proxy:返回的代理对象
- method:当前目标对象使用的方法
- args:当前目标对象使用的方法参数
-
接口
public interface ITeacherDao
{
public void study();
}
目标对象
public class TeacherDao implements ITeacherDao {
@Override
public void Teach() {
System.out.println("我开始学习了!");
}
}
代理对象
public class ProxyFactory {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance() {
/**
* public static studyDao newProxyInstance(ClassLoader loader,
* Class<?>[] interfaces,
* InvocationHandler h)
*/
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 invoke = method.invoke(target, args);
System.out.println("动态代理结束了");
return invoke;
}
});
}
}
实现
public class Client {
public static void main(String[] args) {
ITeacherDao teacherdao = new TeacherDao();
ITeacherDao proxyInstance = (ITeacherDao) new ProxyFactory(teacherdao).getProxyInstance();
proxyInstance.study("小明");
}
}
结果
CGLIB代理
特点:
1、目标对象与代理对象无需再实现任何接口
2、在内存中构建一个子类来实现对目标对象的代理
3、代理对象需要实现MethodInterceptor
重写intercept()
方法
依赖
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
目标对象
public class TeacherDao {
public void Teach(String name) {
System.out.println(name+"开始学习...");
}
}
代理对象
public class ProxyFactory implements MethodInterceptor {
private Object target;
public ProxyFactory(Object target) {
this.target = target;
}
public Object getProxyInstance() {
//创建一个工具类
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(target.getClass());
//设置回调函数
enhancer.setCallback(this);
//创建子类对象、即代理对象
return enhancer.create();
}
//返回的代理对象 当前方法 方法参数
public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("CGLIB动态代理开始");
Object resultValue = method.invoke(target, args);
System.out.println("CGLIB动态代理结束");
return resultValue;
}
}
说明
1、getProxyInstance()
:给目标对象tagert创建一个代理对象
2、重写intercept()
方法来实现目标对象方法的调用
动态代理再说明
Spring AOP 底层使用了动态代理
AOP编程如何选择代理模式:
目标对象需要实现接口:JDK代理
目标对象不需要实现接口:CDLIB代理