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