1、代理模式的分类:
代理模式的定义:为其他对象提供一种代理,以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
代理分为“静态代理”和“动态代理”:静态代理需要我们自己创建代理对象(需要创建代理类),而动态代理的代理对象是自动生成的,我们不需要关心代理对象的生成过程。
2、代理模式中有“抽象角色(接口)”、“代理角色”、“真实角色”这三个角色,代理对象和真实对象都会去实现“抽象角色”这个接口, 也就是说代理模式是基于接口来实现的。
代码
//抽象角色 定义买鞋的方法
public interface Iproduct {
public int product();
}
//真实角色 负责干活
public class LiNingFactory implements Iproduct{
@Override//干活的方法
public int product(){
System.out.println("李宁工厂生产了一双鞋子....定价399");
int price = 399;
return price;
}
}
//代理角色 负责买鞋子
public class LiNingStore implements Iproduct{
Iproduct iproduct;
//把真实对象拿进来 因为后面要找真实对象生产鞋子
public LiNingStore(Iproduct iproduct){
this.iproduct = iproduct;
}
//不生产鞋子 只卖鞋子 鞋子从李宁工厂拿来就好
@Override
public int product() {
int price = iproduct.product();
System.out.println("买了一双"+price+"元的鞋子");
return price;
}
}
public class ProductTest {
public static void main(String[] args) {
//直接找真实对象那么就没有涉及到代理
//Iproduct iproduct = new LiNingFactory();
//iproduct.product();
//真实对象不买鞋子 买鞋子只能找代理
LiNingFactory liNingFactory = new LiNingFactory();
Iproduct iproduct = new LiNingStore(liNingFactory);
iproduct.product();
}
}
//抽象角色
public interface ITarget {
public void show();
}
//真实角色
public class Target implements ITarget{
@Override
public void show(){
System.out.println("真实角色的show方法执行了");
}
}
//代理角色
public class TargetProxy implements ITarget {
private ITarget target; // 目标
public TargetProxy(ITarget target) {
this.target = target;
}
@Override
public void show() {
// 在代理中通过目标来调用真实行为
// 1.例如判断是否有权限调用目标行为
// 2.进行日志操作
// 3.性能临近
target.show();
}
}
/**
* Returns an instance of a proxy class for the specified interfaces
* that dispatches method invocations to the specified invocation
* handler. This method is equivalent to:
* <pre>
* Proxy.getProxyClass(loader, interfaces).getConstructor(new Class[] { InvocationHandler.class }).newInstance(new Object[] { handler });
* </pre>
* @param loader the class loader to define the proxy class
* @param interfaces the list of interfaces for the proxy class
* to implement
* @param h the invocation handler to dispatch method invocations to
* @return a proxy instance with the specified invocation handler of a
* proxy class that is defined by the specified class loader
* and that implements the specified interfaces
* public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
*/
//测试类
public class ProxyTest {
//直接调用目标角色
@Test
public void test1(){
ITarget target = new Target();
target.show();
}
//通过代理对象调用目标角色
@Test
public void test2(){
//1创建目标对象
ITarget target = new Target();
//2创建代理对象
ITarget targetProxy = new TargetProxy(target);
//3通过代理对象调用目标对象的方法
targetProxy.show();
}
//使用JDK提供的Proxy类完成动态代理
@Test
public void test3(){
//1.创建目标对象
final Target target = new Target();
System.out.println("1.创建目标对象");
/*
* 获取类加载器: 目标对象.getClass().getClassLoader();
接口类对象 : 目标对象.getClass().getInterfaces(); class[]
主要是用来获取目标类中所实现的所有的接口数组
InvocationHandler : 监听器
主要功能: 当代理类去调用目标对象中方法的时候,
会先执行监听器中invoke方法, 通过invoke来执行目标对象中方法
*/
//newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
ClassLoader loader = target.getClass().getClassLoader();
Class<?>[] interfaces = target.getClass().getInterfaces();
//2.动态创建代理对象
System.out.println("2.1动态创建代理对象开始");
ITarget newProxyInstance = (ITarget)Proxy.newProxyInstance(loader, interfaces, new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//4执行监听器中invoke方法, 通过invoke来执行目标对象中方法
System.out.println("4.执行监听器中invoke方法, 通过invoke来执行目标对象中方法");
return method.invoke(target, args);
}
});
System.out.println("2.2动态创建代理对象结束");
//3.代理对象调用目标对象中的方法
System.out.println("3.代理对象调用目标对象中的方法");
newProxyInstance.show();
System.out.println("程序结束");
}
}
执行结果:
1.创建目标对象
2.1动态创建代理对象开始
2.2动态创建代理对象结束
3.代理对象调用目标对象中的方法
4.执行监听器中invoke方法, 通过invoke来执行目标对象中方法
真实角色的show方法执行了
程序结束
1、newProxyInstance()详解
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h)
获取类加载器: 目标对象.getClass().getClassLoader();
接口类对象 : 目标对象.getClass().getInterfaces(); class[]
主要是用来获取目标类中所实现的所有的接口数组
InvocationHandler : 监听器
主要功能: 当代理类去调用目标对象中方法的时候, 会先执行监听器中invoke方法, 通过invoke来执行目标对象中方法
- 案例-动态代理完成性能监控
//案例-动态代理完成性能监控
//抽象角色
public interface IUserService {
public String addUser(String userName,String passWord);
}
//目标角色
public class UserServiceimpl implements IUserService{
@Override
public String addUser(String userName, String passWord) {
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
System.out.println("添加用户: 用户名 "+userName+" 密码 "+passWord);
return "hello "+userName;
}
}
public class UserServiceTest {
public static void main(String[] args) {
//1创建目标对象
IUserService userServiceimpl = new UserServiceimpl();
//2创建代理对象
ProxyUtils proxyUtils = new ProxyUtils(userServiceimpl);
IUserService proxy = (IUserService)proxyUtils.getProxy();
//3执行方法
String addUser = proxy.addUser("tom", "123");
System.out.println(addUser);
}
}
/**
* 代理对象工具类
Object invoke(Object proxy,Method method,Object[] args)throws Throwable
在代理实例上处理方法调用并返回结果。在与方法关联的代理实例上调用方法时,将在调用处理程序上调用此方法。
参数:
proxy - 在其上调用方法的代理实例
method - 对应于在代理实例上调用的接口方法的 Method 实例。Method 对象的声明类将是在其中声明方法的接口,
该接口可以是代理类赖以继承方法的代理接口的超接口。
args - 包含传入代理实例上方法调用的参数值的对象数组,如果接口方法不使用参数,则为 null。
基本类型的参数被包装在适当基本包装器类(如 java.lang.Integer 或 java.lang.Boolean)的实例中。
返回:
从代理实例的方法调用返回的值。如果接口方法的声明返回类型是基本类型,
则此方法返回的值一定是相应基本包装对象类的实例;
否则,它一定是可分配到声明返回类型的类型。
如果此方法返回的值为 null 并且接口方法的返回类型是基本类型,
则代理实例上的方法调用将抛出 NullPointerException。
否则,如果此方法返回的值与上述接口方法的声明返回类型不兼容,
则代理实例上的方法调用将抛出 ClassCastException。
*/
public class ProxyUtils implements InvocationHandler{
//成员变量目标对象
private Object target;
public ProxyUtils(Object target){
this.target = target;
}
//成员方法获得代理对象
public Object getProxy(){
ClassLoader loader = target.getClass().getClassLoader();
Class<?>[] interfaces = target.getClass().getInterfaces();
return Proxy.newProxyInstance(loader, interfaces, this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 在调用前,得到一个时间
long start = System.currentTimeMillis();
Object invoke = method.invoke(target, args);
// 在调用后,得到一个时间
long end = System.currentTimeMillis();
long time = end - start;
System.out.println(time);
return invoke;
}
/*
public Object getProxy(){
ClassLoader loader = target.getClass().getClassLoader();
Class<?>[] interfaces = target.getClass().getInterfaces();
return Proxy.newProxyInstance(loader, interfaces, new InvocationHandler(){
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println(method.getName());
System.out.println(args[0]+" "+args[1]);
return method.invoke(target, args);
}
});
}
*/
}