1、简介
1.1 概念
代理就是被代理者(对象)没有能力或者不愿意去完成某件事情,需要找个人(代理对象)代替自己去完成这件事,动态代理就是用来对业务功能(方法)进行代理的。
如歌星(经纪人),买房的人(房产中介)
1.2 动态代理的优点
- 非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接本身做代理。
- 可以为被代理对象的所有方法做代理。
- 可以在不改变方法源码的情况下,实现对方法功能的增强。
- 不仅简化了编程工作、提高了软件系统的可扩展性,同时也提高了开发效率。
2、如何创建代理对象
2.1 主要调用方法
- Java中代理的代表类是:java.lang.reflect.Proxy
Proxy提供了一个静态方法,用于为对象产生一个代理对象返回。要想创建一个代理对象,需要使用Proxy类的newProxyInstance方法。
Proxy.newProxyInstance(ClassLoader 加载器,Class<?> 接口,InvocationHandler h) - newProxyInstance参数:
一个类加载器(class loader)。
一个Class对象数组,每个元素都是需要实现的接口。
一个调用处理器
2.2 创建代理对象步骤
- 必须有接口,被代理对象要实现接口(代理通常是基于接口实现的)。
- 创建一个被代理对象的对象,该对象为业务对象
- 使用Proxy类提供的方法为被代理对象做一个代理对象并返回。
2.3 案例1
接口
package com.proxy;
public interface Skill {
void jump();
void sing();
}
对象
package com.proxy;
public class Star implements Skill{
private String name;
public Star(String name) {
this.name = name;
}
public void jump(){
System.out.println("跳舞");
}
public void sing(){
System.out.println("唱歌");
}
}
创建代理对象的工具类
package com.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class StarAgentProxy {
/*
设计一个方法返回Star对象的代理对象
*/
public static Skill getProxy(Star obj){
//为Star对象生成一个代理对象
return (Skill) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
System.out.println("代理先做一些前操作,再让真正的对象进行方法");
//method代表正在使用的方法,objects代表method方法的参数
Object rs = method.invoke(obj,objects);
System.out.println("做完方法的内容,之后的操作");
//将对象的返回结果返回
return rs;
}
});
}
}
测试
package com.proxy;
public class Test {
public static void main(String[] args) {
//1、创建一个对象,对象的类必须实现接口
Star s = new Star("明星");
//为s创建一个代理对象
Skill s2 = StarAgentProxy.getProxy(s);
s2.jump();//走代理
s2.sing();
}
}
测试结果
代理先做一些前操作,再让真正的对象进行方法
跳舞
做完方法的内容,之后的操作
代理先做一些前操作,再让真正的对象进行方法
唱歌
做完方法的内容,之后的操作
从代码执行结果可以看出通过代理对象调用方法的执行流程是:
先走向代理,让代理做一些辅助工作,开发真正触发对象的方法的执行,回到代理中,由代理将方法的运行结果返回给方法的调用者
2.4 案例2
package com.tetsproxy;
public interface UserService {
String login(String loginName,String passWord);
void deleteUsers();
String selectUsers();
}
package com.tetsproxy;
public class UserServiceImpl implements UserService{
@Override
public String login(String loginName, String passWord) {
// long startTime = System.currentTimeMillis();
String rs = "登录名称密码错误";
if("admin".equals(loginName)&&"111222".equals(passWord)){
rs = "登录成功";
}
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// long endtTime = System.currentTimeMillis();
// System.out.println("login方法耗时"+(endtTime - startTime) / 1000.0 + "s");
return rs;
}
@Override
public void deleteUsers() {
// long startTime = System.currentTimeMillis();
try {
System.out.println("正在删除用户数据");
Thread.sleep(2500);
} catch (InterruptedException e) {
e.printStackTrace();
}
// long endtTime = System.currentTimeMillis();
// System.out.println("deleteUsers方法耗时"+(endtTime - startTime) / 1000.0 + "s");
}
@Override
public String selectUsers() {
// long startTime = System.currentTimeMillis();
String rs = "查询10000条数据";
try {
System.out.println("查询10000条数据");
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
// long endtTime = System.currentTimeMillis();
// System.out.println("selectUsers方法耗时"+(endtTime - startTime) / 1000.0 + "s");
return rs;
}
}
package com.tetsproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyUtil {
public static UserService getProxy(UserService obj){
return (UserService)Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), new InvocationHandler() {
@Override
public Object invoke(Object o, Method method, Object[] objects) throws Throwable {
long startTime = System.currentTimeMillis();
Object rs = method.invoke(obj,objects);
long endtTime = System.currentTimeMillis();
System.out.println(method.getName()+"方法耗时"+(endtTime - startTime) / 1000.0 + "s");
return rs;
}
});
}
}
package com.tetsproxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class TestTime {
public static void main(String[] args) {
// UserService u = new UserServiceImpl();
// System.out.println(u.login("admin", "111222"));
// System.out.println(u.selectUsers());
// u.deleteUsers();
//上面的代码实现会有很多重复代码
UserService u = ProxyUtil.getProxy(new UserServiceImpl());
System.out.println(u.login("admin", "111222"));
System.out.println(u.selectUsers());
u.deleteUsers();
}
}
测试结果
login方法耗时1.015s
登录成功
查询10000条数据
selectUsers方法耗时3.012s
查询10000条数据
正在删除用户数据
deleteUsers方法耗时2.513s
如果想要实现任意接口都能用此代码进行代码可以将代码工具类的类型改为泛型