代理其实就是一种模式,其目的就是为了解决在直接访问对象时带来的问题
二、代理模式
代理模式是常用的java设计模式,特征是代理类与委托类有同样的接口,代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后处理消息等
代理类与委托类之间通常会存在关联关系,一个代理类的对象与一个委托类的对象关联,代理类的对象本身并不真正实现服务,而是通过调用委托类的对象的相关方法,来提供特定的服务。
按照代理的创建时期,代理类可以分为两种:
静态代理:由程序员创建或特定工具自动生成源代码再对其编译。在程序运行前代理类的.class文件就已经存在了。
动态代理:在程序运行时运用反射机制动态创建而成。
三、单个静态代理
public interface CountDao {
// 查看账户方法
public void queryCount();
}
public class CountDaoImpl implements CountDao {
public void queryCount() {
System.out.println("查看账户方法...");
}
}
public class CountTrancProxy implements CountDao {
private CountDao countDao;
public CountProxy(CountDao countDao) {
this.countDao = countDao;
}
@Override
public void queryCount() {
System.out.println("tranc start");
countDao.queryCount();
System.out.println("tranc end");
}
}
public class TestCount {
public static void main(String[] args) {
CountTrancProxy countProxy = new CountTrancProxy(new CountDaoImpl());
countProxy.updateCount();
}
}
四、多个静态代理
public class CountLogProxy implements CountDao {
private CountDao countDao;
public CountLogProxy(CountDao countDao) {
this.countDao = countDao;
}
@Override
public void queryCount() {
System.out.println("Log start");
countDao.queryCount();
System.out.println("Log end");
}
}
调用:
// 体现了聚合的思想,代理之间的组合
public static void main(String[] args) {
CountTrancProxy trancProxy = new CountTrancProxy(new CountDaoImpl());
CountLogProxy logPro = new CountLogProxy(trancProxy);
logPro.queryCount();
}
输出:
Log start
事务处理之前
查看账户方法...
事务处理之后
Log end
五、静态代理的问题
(1)、代理类和委托类实现了相同的接口,代理类通过委托类实现了相同的方法。这样做会造成大量的代码冗余。若一个接口增加了一个方法,代理类和接口实现类都必须实现该方法。增加了代码的维护难度、
(2)代理对象只服务于一种特定类型的对象,假如要服务于多种类型的对象,代理类就显得捉襟见肘、力不从心了
六、动态代理
IUserService接口:
package com.hap.proxy;
public interface IUserService {
void addFriend();
void addGroup();
void publishLog();
void publishComments();
void publishWords();
void deleteWords();
}
Permission注解:
package com.hap.proxy;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Permission {
public String value();
}
接口实现类:
package com.hap.proxy;
//被代理对象
public class UserService implements IUserService{
@Override
@Permission("添加好友")
public void addFriend() {
System.out.println("添加了好友");
}
@Override
@Permission("添加群组")
public void addGroup() {
System.out.println("添加了群组");
}
@Override
@Permission("发布日志")
public void publishLog() {
System.out.println(" 发布了日志");
}
@Override
@Permission("发布评论")
public void publishComments() {
System.out.println("发布了评论");
}
@Override
@Permission("发布留言")
public void publishWords() {
System.out.println("发布了留言");
}
@Override
public void deleteWords() {
System.out.println("删除了留言");
}
}
用户实体类:
package com.hap.proxy;
import java.util.ArrayList;
public class User{
private String username;
private String password;
/**
* 保存用户权限集合
*/
private ArrayList<String> list = new ArrayList<String>();
public User() {
super();
// TODO Auto-generated constructor stub
}
public User(String username, String password) {
super();
this.username = username;
this.password = password;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public ArrayList<String> getList() {
return list;
}
public void setList(ArrayList<String> list) {
this.list = list;
}
@Override
public String toString() {
return "User [username=" + username + ", password=" + password + "]";
}
}
UserDao模拟数据库(为客户端提供假数据)
package com.hap.proxy;
import java.util.ArrayList;
public class UserDao {
private static ArrayList<User> userList = new ArrayList<User>();
static {
User u1 = new User("itcast", "itcast");
u1.getList().add("添加好友");
u1.getList().add("删除评论");
userList.add(u1);
User u2 = new User("itheima", "itheima");
u2.getList().add("添加好友");
u2.getList().add("删除评论");
u2.getList().add("添加群组");
userList.add(u2);
}
public static User getUser(String username, String password) {
for (User user : userList) {
if (username.equals(user.getUsername()) && password.equals(user.getPassword())) {
return user;
}
}
return null;
}
}
代理对象工厂
package com.hap.proxy;
import java.lang.annotation.Annotation;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ServiceFactory {
public static IUserService getService(User user) {
UserService userService = new UserService();
ClassLoader loader = userService.getClass().getClassLoader();
Class<?>[] interfaces = userService.getClass().getInterfaces();
MyInvocationHandler h = new MyInvocationHandler(userService, user);
// 通过Proxy创建代理对象
IUserService service = (IUserService) Proxy.newProxyInstance(loader, interfaces, h);
return service;
}
}
class MyInvocationHandler implements InvocationHandler {
private UserService userService;
private User user;
public MyInvocationHandler(UserService userService, User user) {
this.userService = userService;
this.user = user;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// 拿到方法名字
String name = method.getName();
// 拿到方法的参数
Class<?>[] parameterTypes = method.getParameterTypes();
// 通过反射获取UserInterfaceImpl里面的方法
Method m = userService.getClass().getMethod(name, parameterTypes);
// 获取方法上面的 注解
Permission userAnnotation = m.getAnnotation(Permission.class);
// 获取注解里面的参数内容,然后与用户的权限进行比较
if (null == userAnnotation) {
System.out.println("执行该方法不需要权限");
return method.invoke(userService, args);
}
// 如果注解内容不为空,说明需要权限才能有这个操作
if (user.getList().contains(userAnnotation.value())) {
System.out.println("该操作需要权限,但是" + user.getUsername() + " 具有该权限");
return method.invoke(userService, args);
} else {
System.out.println("该操作需要权限,但是" + user.getUsername() + " 不具有该权限");
}
return null;
}
}
客户端:
package com.hap.proxy;
import java.util.Scanner;
public class UserClient {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
System.out.println("请输入涌户名:");
String username = br.readLine();
System.out.println("请输入密码:");
String password = br.readLine();
// 校验(不管校验是否成功都要返回结果)
User user = UserDao.getUser(username, password);
if (null == user) {
System.out.println("用户不存在");
return;
}
System.out.println("欢迎登陆");
while (true) {
System.out.println("请选择操作:1.添加好友 2.添加群组 3.发布日志 4.发布评论 5.发不留言 6.删除留言 7.退出");
// 获取一个代理对象
IUserService userInterface = UserSeriveFactory.getService(user);
String choice = br.readLine();
switch (choice) {
case "1":
userInterface.addFriend();
break;
case "2":
userInterface.addGroup();
break;
case "3":
userInterface.publishLog();
break;
case "4":
userInterface.publishComments();
break;
case "5":
userInterface.publishWords();
break;
case "6":
userInterface.deleteWords();
break;
case "7":
default:
System.out.println("谢谢使用");
return;
}
}
}