当我们说道代理的时候脑海里出现的是代理模式,没错,这是比较专业的说法。代理模式的实现形式可以分为:静态代理和动态代理两种。根据技术又有jdk代理,cglib代理两种。下面我就根据自己浅薄的学习说一下代理。
代理:根据汉语的意思就是:代替他人进行相应的操作,我们想要找一个明星唱歌,那么我就要找他的经纪人,然后经纪人再找明星,经纪人所做的作用就是代理。那么这就很明白了,代理分为代理类(经纪人),委托类(明星),代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等。而主要的逻辑是委托类实现的。
从上面的话语我们就知道代理模式的好处:
- 代理对象的价值就是帮助委托类进行拦截,事前处理,事后善后,保护委托类的隐私,拦截对委托类的真实访问
- 代理类应该跟委托类具有相同的功能,或者代理类会根据用户传过来的信息进行处理,然后决定调用委托类的方法
说了这么多想必大家就问了,代理技术都是要运行在哪些地方呢?其实java的代理技术是一个很重要的技术,在很多地方都有运行到,比如springAOP技术。运行的场景就更多啦:预处理消息、过滤消息等功能。
说了这么多下面开始说代理的实现:
静态代理:所谓的静态代理就是在程序运行前,代理类的class文件已经存在,是静态的,不是在程序运行过程中,根据信息而动态创建的,
静态代理组成部分有三种:公共的接口,代理类,委托类
接口:
package com.fg.proxy;
/**
* @version 1.0
* @filename ISubject
* @author fg
* @date 2018-06-08
* @describe 测试静态代理,接口声明
* @history 2018-06-08 1.0
*/
public interface ISubject {
/**
* @version 1.0
* @methodName doSomething
* @author: wyf
* @date 2018-06-09
* @describe 定义代理接口方法
* @history 2018-06-09 定义
*/
public void doSomething();
}
委托类:实现真正的逻辑
package com.fg.proxy.impl;
import java.util.concurrent.ThreadPoolExecutor;
import com.fg.proxy.ISubject;
/**
* @version 1.0
* @filename RealSubjectImpl
* @author fg
* @date 2018-06-08
* @describe 静态代理接口实现类,测试静态代理服务
* @history 2018-06-08 1.0
*/
public class RealSubjectImpl implements ISubject {
/**
* @version 1.0
* @methodName doSomething
* @author: wyf
* @date 2018-06-09
* @describe 实现代理方法代理接口方法
* @history 2018-06-09 定义
*/
@Override
public void doSomething() {
try {
Thread.sleep(1000);
System.out.println("暂停1000ms,重新开始跑");
} catch (InterruptedException e) {
System.out.println(e.toString());
}
}
}
代理类:实现同样的接口,包含一个委托类的私有对象,在相同的方法中加入必要的处理逻辑,然后调用委托类对象真正的逻辑接口。代理服务因为不知道真正的逻辑实现逻辑是多久,一般会打印委托类运行时间
package com.fg.proxy.impl;
import com.fg.proxy.ISubject;
/**
* @version 1.0
* @filename ProxySubjectImpl
* @author wyf
* @date 2018-06-08
* @describe 测试静态代理,接口声明
* @history 2018-06-08 1.0
*/
public class ProxySubjectImpl implements ISubject {
private ISubject subject;
/*
* @version 1.0
*
* @author FG
*
* @methodName ProxySubjectImpl
*
* @params sub 委托类
*
* @description 构造,初始化委托类
*
* @history:2018-06-09 创建
*/
public ProxySubjectImpl(ISubject sub) {
this.subject = sub;
}
/*
* @version 1.0
*
* @author FG
*
* @methodName ProxySubjectImpl
*
* @params sub 委托类
*
* @return void
*
* @description 构造,实现接口函数,调用委托类的功能进行
*
* @history:2018-06-09 创建
*/
@Override
public void doSomething() {
long l_startTime = System.currentTimeMillis();
this.subject.doSomething();
long l_endTime = System.currentTimeMillis();
System.out.println("程序运行时间: " + (l_endTime - l_startTime) + "ms");
}
/*
* @version 1.0
*
* @author FG
*
* @methodName doSleep1000ms
*
* @params
*
* @return void
*
* @description 延迟1000ms
*
* @history:2018-06-09 创建
*/
public void doSleep1000ms() {
long l_startTime = System.currentTimeMillis();
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
System.out.println("延迟失败,原因:" + e.toString());
}
long l_endTime = System.currentTimeMillis();
System.out.println("程序运行时间:" + (l_endTime - l_startTime) + "ms");
}
}
到现在我们就完成了一个简单的静态代理实现,那么就可以写一个main函数调用。
public class ProxyMain {
/*
* @version 1.0
*
* @author FG
*
* @methodName main
*
* @params
*
* @description 方法入口函数
*
* @history:2018-06-09. 创建
*/
public static void main(String agrs[]) {
ISubject proxySub = ProxySubjectFactory.getInstanceProxy();
proxySub.doSomething();
}
}
动态代理:
动态代理接口
package com.fg.proxy;
/**
* @version 1.0
* @filename IDynamicProxy
* @author wyf
* @date 2018-06-09
* @describe 动态代理接口
* @history 2018-06-09 1.0
*/
public interface IDynamicProxy {
/*
* @version 1.0
*
* @author FG
*
* @methodName singSong
*
* @params musicCode
*
* @return void
*
* @description 唱8
*
* @history:2018-06-09 创建
*/
public void singSong(String musicCode);
/*
* @version 1.0
*
* @author FG
*
* @methodName danceDj
*
* @params dancerStr
*
* @return void
*
* @description 跳舞
*
* @history:2018-06-09 创建
*/
public void danceDj(String dancerStr);
}
动态代理委托类实现:
package com.fg.proxy.impl;
import com.fg.proxy.IDynamicProxy;
/**
* @version 1.0
* @filename DynamicProxyImpl
* @author wyf
* @date 2018-06-09
* @describe 实现动态代理
* @history 2018-06-09 1.0
*/
public class DynamicProxyImpl implements IDynamicProxy {
/*
* @version 1.0
*
* @author FG
*
* @methodName singSong
*
* @params musicCode
*
* @return void
*
* @description 唱8
*
* @history:2018-06-09 创建
*/
@Override
public void singSong(String musicCode) {
try {
System.out.println("所唱歌曲:"+musicCode);
Thread.sleep(1000);
System.out.println("唱歌结束!");
} catch (InterruptedException e) {
System.out.println("唱歌时候报错");
}
}
/*
* @version 1.0
*
* @author FG
*
* @methodName danceDj
*
* @params dancerStr
*
* @return void
*
* @description 跳舞
*
* @history:2018-06-09 创建
*/
@Override
public void danceDj(String dancerStr) {
System.out.println("所跳舞蹈:"+dancerStr);
try {
Thread.sleep(1000);
System.out.println("跳舞结束!");
} catch (InterruptedException e) {
System.out.println("唱歌报错!"+e.toString());
}
}
}
动态代理实现需要运用java的java.lang.reflect.proxy类和实现接口java.lang.reflect.InvocationHandler
实现接口InvocationHandler:
package com.fg.proxy.impl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import com.fg.util.MutilUtil;
/**
* @version 1.0
* @filename DynamicProxyInvocationHanlder
* @author FG
* @date 2018-06-11
* @describe 实现InvocationHanlder接口,动态实现
* @history 2018-06-11 1.0
*/
public class DynamicProxyInvocationHanlder<T> implements InvocationHandler {
// 委托类的实例
private T targer;
/*
* @version 1.0
*
* @author FG
*
* @methodName DynamicProxyInvocationHanlder
*
* @params
*
* @return void
*
* @description 构造函数,初始化委托类的实例
*
* @history:2018-06-11 创建
*/
public DynamicProxyInvocationHanlder(T t_targer) {
this.targer = t_targer;
}
/*
* @version 1.0
*
* @author FG
*
* @methodName invoke
*
* @params proxy 动态代理对象,method 动态调用的方法,arg2 调用委托类的参数数组
*
* @return Object 返回
*
* @description 动态调用方法
*
* @history:2018-06-11 创建
*/
@Override
public Object invoke(Object proxy, Method method, Object[] arg2) throws Throwable {
System.out.println("代理执行" + method.getName() + "方法");
MutilUtil.startTime();
Object result = method.invoke(targer, arg2);
MutilUtil.endTime();
return result;
}
}
工具类:
package com.fg.util;
/**
* @version 1.0
* @filename MutilUtil
* @author FG
* @date 2018-06-11
* @describe 综合工具类
* @history 2018-06-11 1.0
*/
public class MutilUtil {
private static ThreadLocal<Long> threadLocal = new ThreadLocal<>();
/*
* @version 1.0
*
* @author FG
*
* @methodName startTime
*
* @params
*
* @return void
*
* @description 运行到当前的时间
*
* @history:2018-06-11 创建
*/
public static void startTime() {
threadLocal.set(System.currentTimeMillis());
System.out.println("开始时间:"+threadLocal.get()+"ms" );
}
/*
* @version 1.0
*
* @author FG
*
* @methodName endTime
*
* @params
*
* @return void
*
* @description 结束时间
*
* @history:2018-06-11 创建
*/
public static void endTime() {
Long l_endTime = System.currentTimeMillis();
System.out.println("程序运行耗时:"+ (l_endTime - threadLocal.get())+"ms");
}
}
实现调用动态代理类:
IDynamicProxy dynamicProxy = new DynamicProxyImpl();
DynamicProxyInvocationHanlder<IDynamicProxy> dynProxyHandler = new DynamicProxyInvocationHanlder<IDynamicProxy>(dynamicProxy);
IDynamicProxy LDHProxy =(IDynamicProxy) Proxy.newProxyInstance(IDynamicProxy.class.getClassLoader(), new Class<?>[] {IDynamicProxy.class}, dynProxyHandler);
LDHProxy.singSong("wangyafei");
LDHProxy.danceDj("xiaotiane");
到现在动态代理就实现了,刚开始学习的时候我有一个疑问,proxy类调用的机制是什么?通过查询很多资料我才知道原来proxy在调用newProxyInstance函数的时候指定了类的加载器,类的接口,然后根据Invocationhanlder,返回去一个代理类对象,每一次调用代理对象的方法的时候,都会调用Invocationhanlderi的invoke函数,根据函数名和参数调用委托类的同名方法。