代理模式即为其他对象提供一种代理以控制对目标(真实)对象的访问,并且可在不改变目标(真实)对象情况下拓展一些额外的功能。
代理对象负责为目标(真实)对象预处理消息,过滤消息并转发消息,以及进行消息被目标(真实)对象执行后的后续处理。
代理模式涉及的角色:
抽象角色:声明真实对象和代理对象的共同接口或抽象类;
代理角色:代理对象真实角色内部含有对真实对象的引用,从而可以操作真实对象,同时代理对象提供与真实对象相同的接口以便在任何时刻都能代替真实对象。同时,代理对象可以在执行真实对象操作时,附加其他的操作,相当于对真实对象进行封装。
真实角色:代理角色所代表的真实对象,是我们最终要引用的对象。
一、静态代理
IUserDao.java(抽象角色:真实对象和代理对象的共同接口)
package cn.iborder.Dao;
/**
* 抽象角色
* @author iborder
*/
public interface IUserDao {
void findUsers();
}
UserDao.java(真实对象)
package cn.iborder.Dao.impl;
import cn.iborder.Dao.IUserDao;
/**
* 真实角色
* @author iborder
*/
public class UserDao implements IUserDao {
@Override
public void findUsers() {
// TODO Auto-generated method stub
System.out.println(this.getClass().getSimpleName()+"执行真实对象的操作");
}
}
TestProxy.java(代理对象)
package cn.iborder.test;
import org.junit.Test;
import cn.iborder.Dao.IUserDao;
import cn.iborder.Dao.impl.UserDao;
/**
* 代理角色
* @author iborder
*/
public class TestProxy implements IUserDao{
IUserDao userDao;
public void setUsersDao(IUserDao userDao) {
this.userDao = userDao;
}
@Override
public void findUsers() {
// TODO Auto-generated method stub
System.out.println(this.getClass().getSimpleName()+"代理对象附加的操作,执行前");
if (userDao == null) {
userDao = new UserDao();
}
userDao.findUsers();
System.out.println(this.getClass().getSimpleName()+"代理对象附加的操作,执行后");
}
@Test
public void test() {
IUserDao userDao = new TestProxy();
userDao.findUsers();
}
}
运行结果:
TestProxy代理对象附加的操作,执行前
UserDao执行真实对象的操作
TestProxy代理对象附加的操作,执行后
静态代理缺点:
1、真实角色必须是实现已经存在的,并将其作为代理对象的内部属性。因为代理对象需要实现与目标对象一样的接口,如果大量使用会导致类的急剧膨胀;
2、一旦接口增加方法,目标对象和代理对象都要维护。
二、动态代理
“代理角色”将不用手动生成,而由JVM在运行时,通过指定类加载器、接口数组、调用处理程序这3个参数来动态生成。
Java 用于实现动态代理机制的类是java.lang.reflect.Proxy,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
使用动态代理的对象必须实现一个或多个接口。
Proxy方法摘要
static InvocationHandler getInvocationHandler(Object proxy) | 返回指定代理实例的调用处理程序。 |
---|---|
static Class<?> getProxyClass(ClassLoader loader, Class<?>... interfaces) | 返回代理类的 java.lang.Class 对象,并向其提供类加载器和接口数组。 |
static boolean isProxyClass(Class<?> class) | 当且仅当指定的类通过getProxyClass方法或newProxyInstance方法动态生成为代理类时,返回 true。 |
static Object newProxyInstance (ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) | 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序。 |
static Object newProxyInstance(
ClassLoader loader, //定义代理类的类加载器
Class<?>[] interfaces, //代理类要实现的接口列表
InvocationHandler h //指派方法调用的调用处理程序
)
示例:
ProxyFactory.java
package cn.iborder.factory;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import cn.iborder.Dao.IUserDao;
import cn.iborder.Dao.impl.UserDao;
public class ProxyFactory {
private Object target; //目标对象
public ProxyFactory(Object target) {
// TODO Auto-generated constructor stub
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 {
// TODO Auto-generated method stub
System.out.println(this.getClass().getSimpleName()+"代理对象附加的操作,执行前");
//mehtod代表目标对象被调用的方法名
System.out.println(method.getName());
// 执行目标对象方法
Object result = method.invoke(target, args);
System.out.println(this.getClass().getSimpleName()+"代理对象附加的操作,执行后");
return result;
}
});
}
public static void main(String[] args) {
IUserDao target = new UserDao();
IUserDao userDao = (IUserDao) new ProxyFactory(target).getProxyInstance();
userDao.findUsers();
}
}
运行结果:
代理对象附加的操作,执行前
findUsers
UserDao执行真实对象的操作
代理对象附加的操作,执行后