一、概述
(一)代理的概念: 某些场景下对象会找一个代理对象辅助完成工作。
(二)代理的作用: 为了防止外部直接调用功能,需要中间对象代理实际对象完成功能调用并可执行额外功能。
(三)代理对象 java,lang.reflect.Proxy API
方法 | 说明 |
---|---|
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h) | 指定类加载器、代理类接口列表、处理程序获取代理类 |
(三)代理的工作原理:
二、初步使用
/*
* 以歌手与经纪人关系做解释
*/
public class ProxyDemo {
public static void main(String[] args) {
//1、创建实际对象(歌手)
Singer singer = new Singer("歌手");
singer.work();
//2、创建代理
work proxy = SingerProxy.getProxy(singer);
proxy.sing();
proxy.dance();
}
}
interface work{
void dance();
void sing();
}
class Singer implements work{
private String name;
public Singer() {
}
public Singer(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public void sing(){
System.out.println(this.name + "正在唱歌");
}
public void dance(){
System.out.println(this.name + "正在跳舞");
}
public void work(){
sing();
dance();
}
@Override
public String toString() {
return "Singer{" +
"name='" + name + '\'' +
'}';
}
}
class SingerProxy{
public static work getProxy(Singer singer){
return (work) Proxy.newProxyInstance(
//类加载器
singer.getClass().getClassLoader(),
//对象接口实现列表
singer.getClass().getInterfaces(),
//核心程序
new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("收款");
Object res = method.invoke(singer,args);
System.out.println("给周边");
return res;
}
}
);
}
}
/*打印输出*/
歌手正在唱歌
歌手正在跳舞
收款
歌手正在唱歌
给周边
收款
歌手正在跳舞
给周边
三、应用案例
案例:性能分析
需求:将每个功能耗时统计出来。
public class ProxyTest {
public static void main(String[] args) {
UserLogin userLogin = UserLoginProxy.userLogin(new UserLoginImpl());
System.out.println(userLogin.login("admin", "123456"));
userLogin.select();
userLogin.delete();
}
}
interface UserLogin{
String login(String uname, String password);
void delete();
void select();
}
class UserLoginImpl implements UserLogin{
@Override
public String login(String uname, String password) {
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
return uname.equals("admin") && password.equals("123456") ? "登录成功":"登录失败";
}
@Override
public void delete() {
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
@Override
public void select() {
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
}
}
class UserLoginProxy{
public static UserLogin userLogin(UserLogin impl){
return (UserLogin) Proxy.newProxyInstance(impl.getClass().getClassLoader(), impl.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
long start = System.currentTimeMillis();
Object o = method.invoke(impl,args);
long end = System.currentTimeMillis();
System.out.println("=========="+method.getName()+"()方法,时间:"+(end - start)+" s ==========");
return o;
}
});
}
}
/*打印输出*/
==========login()方法,时间:1005 s ==========
登录成功
==========select()方法,时间:2503 s ==========
==========delete()方法,时间:2506 s ==========
动态代理的优点
- 在不改变方法源码的情况下,增强方法功能,提高代码复用
- 简化编程工作、提高开发效率,同时提高软件系统扩展性
- 可以为实际对象的所有方法做代理
- 灵活,支持任意接口类型的实现类对象做代理,或直接为接口本身做代理