Java动态代理--思想
动态代理
案例引入
-
需求
模拟某企业用户管理业务,需包含用户登录,用户删除,用户查询功能,并要统计每个功能的耗时。
-
分析
定义一个UserService表示用户业务接口,规定必须完成用户登录,用户删除,用户查询功能。
定义一个实现类UserServiceImpl实现UserService,并完成相关功能,且统计每个功能的耗时。
定义测试类,创建实现类对象,调用方法。
示例代码
/*
模拟用户业务功能
*/
public interface UserService {
String login(String username,String password);
void findUser();
boolean removeUser();
}
public class UserServiceImpl implements UserService{
@Override
public String login(String username, String password) {
long startTime = System.currentTimeMillis();
try{
Thread.sleep(1000);
if ("admin".equals(username) && "123".equals(password)) {
return "success";
}
return "用户名或密码有误";
}catch (Exception e){
e.printStackTrace();
return "error";
}finally {
long endTime = System.currentTimeMillis();
System.out.println("login 花费了:"+(endTime-startTime)/1000+"s");
}
}
@Override
public void findUser() {
long startTime = System.currentTimeMillis();
System.out.println("找到300个用户信息");
try{
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}finally {
long endTime = System.currentTimeMillis();
System.out.println("findUser 花费了:"+(endTime-startTime)/1000+"s");
}
}
@Override
public boolean removeUser() {
long startTime = System.currentTimeMillis();
System.out.println("删除 300个用户信息");
try{
Thread.sleep(500);
return true;
}catch (Exception e){
e.printStackTrace();
return false;
}finally {
long endTime = System.currentTimeMillis();
System.out.println("removeUser 花费了:"+(endTime-startTime)/1000+"s");
}
}
}
public class Test {
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
System.out.println(userService.login("admin","123"));
System.out.println(userService.removeUser());
userService.findUser();
}
}
案例存在问题
- 每个方法都要进行性能统计
- 大量重复的代码
解决案例问题–动态代理
什么是动态代理
代理就是被代理者没有能力或者不愿意去完成某件事情,需要找个人代替自己去完成这件事,动态代理就是用来对业务功能(方法)进行代理的
动态代理关键步骤
- 必须有接口,实现类要实现接口(代理通常是基于接口实现的)。
- 创建一个实现类的对象,该对象为业务对象,紧接着为业务对象做一个代理对象。
示例代码
/*
模拟用户业务功能
*/
public interface UserService {
String login(String username,String password);
void findUser();
boolean removeUser();
}
public class UserServiceImpl implements UserService{
@Override
public String login(String username, String password) {
try{
Thread.sleep(1000);
if ("admin".equals(username) && "123".equals(password)) {
return "success";
}
return "用户名或密码有误";
}catch (Exception e){
e.printStackTrace();
return "error";
}
}
@Override
public void findUser() {
System.out.println("找到300个用户信息");
try{
Thread.sleep(2000);
}catch (Exception e){
e.printStackTrace();
}
}
@Override
public boolean removeUser() {
System.out.println("删除 300个用户信息");
try{
Thread.sleep(500);
return true;
}catch (Exception e){
e.printStackTrace();
return false;
}
}
}
PRoxyUtil 动态代理工具类
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
参数:
参数一:类加载器,负责加载代理类到内存中使用
参数二:获取被代理的对象实现的全部接口,代理腰围全部接口的 全部方法进行代理
参数三:代理的核心处理逻辑
*/
public class ProxyUtil {
/*
生成业务对象的代理对象
@param userService
@return
*/
public static UserService getProxy(UserServiceImpl userService) {
// 返回了一个代理对象
return (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces()
, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 参数一: 代理对象本身
// 参数二: 正在被代理的方法
// 参数三: 被代理方法应传入的参数
long startTime = System.currentTimeMillis();
// 马上触发方法的真正执行(触发真正的业务功能)
Object res = method.invoke(userService, args);
long endTime = System.currentTimeMillis();
System.out.println("removeUser 花费了:"+(endTime-startTime)/1000+"s");
// 把业务动能方法执行的结构返回给调用者
return res;
}
});
}
}
Test 测试类
public class Test {
public static void main(String[] args) {
// 1.把业务对象直接做成一个代理对象返回,代理对象的类型也是 UserService
// UserService userService = new UserServiceImpl();
UserService userService = ProxyUtil.getProxy(new UserServiceImpl());
System.out.println(userService.login("admin","123"));
System.out.println(userService.removeUser());
userService.findUser();
}
}
动态代理的优点
- 非常的灵活,支持任意接口类型的实现类对象做代理,也可以直接为接本身做代理。
- 可以为被代理对象的所有方法做代理。
- 可以在不改变方法源码的情况下,实现对方法功能的增强。
- 不仅简化了编程工作、提高了软件系统的可扩展性,同时也提高了开发效率。
任意接口的实现类做做代理代码示例
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/*
public static Object newProxyInstance(ClassLoader loader,Class<?>[] interfaces,InvocationHandler h)
参数:
参数一:类加载器,负责加载代理类到内存中使用
参数二:获取被代理的对象实现的全部接口,代理腰围全部接口的 全部方法进行代理
参数三:代理的核心处理逻辑
*/
public class ProxyUtil {
/*
生成业务对象的代理对象
@param userService
@return
*/
public static <T> T getProxy(T obj) {
// 返回了一个代理对象
return (T) Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces()
, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 参数一: 代理对象本身
// 参数二: 正在被代理的方法
// 参数三: 被代理方法应传入的参数
long startTime = System.currentTimeMillis();
// 马上触发方法的真正执行(触发真正的业务功能)
Object res = method.invoke(obj, args);
long endTime = System.currentTimeMillis();
System.out.println("removeUser 花费了:"+(endTime-startTime)/1000+"s");
// 把业务动能方法执行的结构返回给调用者
return res;
}
});
}
}
= System.currentTimeMillis();
System.out.println(“removeUser 花费了:”+(endTime-startTime)/1000+“s”);
// 把业务动能方法执行的结构返回给调用者
return res;
}
});
}
}