Jdk 动态代理:利用java的反射,允许运行时动态地创建一个代理类,实现一个或多个接口,将方法的调用转发到你所指定的类。
问题场景:
有一个Person类,其中属性字段有:姓名name、性别gender、兴趣interests、评分值hotOrNotRating,要求:get方法所有字段,对于所有该类实例拥有者或者非该类实例拥有者都有效,而该类实例拥有者除了不能给自己评分之外,可以修改所有的其他字段,而非该类实例拥有者只能设置该评分值,而不能修改其他所有的字段。
利用Java动态代理实现代码如下:
PersonBean.java 类如下:
public interface PersonBean {
String getName(); // 取得人的名字
String getGender(); // 性别
String getInterests(); // 兴趣
int getHotOrNotRating(); // HotOrNot评分(1到10)
void setName(String name);
void setGender(String name);
void setInterests(String interests);
void setHotOrNotRating(int rating);
}
PersonBeanImpl.java 类如下:
public class PersonBeanImpl implements PersonBean {
String name;
String gender;
String interests;
int rating; //当前的评价分数
int ratingCount = 0; // 当前的评价数
@Override
public String getName() {
return name;
}
@Override
public String getGender() {
return gender;
}
@Override
public String getInterests() {
return interests;
}
@Override
public int getHotOrNotRating() {
if (ratingCount == 0) return 0;
return (rating/ratingCount);
}
@Override
public void setName(String name) {
this.name = name;
}
@Override
public void setGender(String name) {
this.gender = gender;
}
@Override
public void setInterests(String interests) {
this.interests = interests;
}
@Override
public void setHotOrNotRating(int rating) {
this.rating += rating;
ratingCount++;
}
}
拥有者使用类的情况:
OwnerInvocationHandler.java 类如下:
**
* 拥有者使用类的情况
*/
public class OwnerInvocationHandler implements InvocationHandler {
PersonBean person;
public OwnerInvocationHandler(PersonBean person){
this.person = person;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException {
try {
if (method.getName().startsWith("get")){
return method.invoke(person, args);
} else if (method.getName().equals("setHotOrNotRating")) {
throw new IllegalAccessException();
} else if (method.getName().startsWith("set")) {
return method.invoke(person, args);
}
} catch (InvocationTargetException e) { // 真正主题抛出异常
e.printStackTrace();
}
return null; // 如果调用其他的方法,一律不理,返回null
}
}
非拥有者使用类如下:
NonOwnerInvocationHandler.java 类如下:
public class NonOwnerInvocationHandler implements InvocationHandler {
PersonBean person;
public NonOwnerInvocationHandler(PersonBean person) {
this.person = person;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws IllegalAccessException {
try {
if (method.getName().startsWith("get")){
return method.invoke(person, args);
} else if (method.getName().equals("setHotOrNotRating")) {
return method.invoke(person, args);
} else if (method.getName().startsWith("set")) {
throw new IllegalAccessException();
}
} catch (InvocationTargetException e) { // 真正主题抛出异常
e.printStackTrace();
}
return null; // 如果调用其他的方法,一律不理,返回null
}
}
测试类如下:
MatchMakikngTestDrive.java 类:
public class MatchMakingTestDrive {
public static void main(String[] args) {
MatchMakingTestDrive test = new MatchMakingTestDrive();
test.drive();
}
public void drive() {
PersonBean joe = new PersonBeanImpl();
joe.setName("tim"); joe.setGender("girl"); joe.setInterests("watch movies"); joe.setHotOrNotRating(0);
PersonBean ownerProxy = getOwnerProxy(joe);
System.out.println("Name is: " + ownerProxy.getName());
ownerProxy.setInterests("bowling, Go");
System.out.println("Interests set from owner proxy");
try {
ownerProxy.setHotOrNotRating(10);
} catch (Exception e) {
System.out.println("Can't set rating from owner proxy");
}
System.out.println("Rating is " + ownerProxy.getHotOrNotRating());
PersonBean nonOwnerProxy = getNonOwnerProxy(joe);
System.out.println("Name is: " + nonOwnerProxy.getName());
try {
nonOwnerProxy.setInterests("bowling, go");
} catch (Exception e) {
System.out.println("Can't set interests from non owner proxy");
}
nonOwnerProxy.setHotOrNotRating(3);
System.out.println("Rating set from non owner proxy");
System.out.println("Rating is " + nonOwnerProxy.getHotOrNotRating());
}
PersonBean getOwnerProxy(PersonBean person) {
return (PersonBean) Proxy.newProxyInstance(person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
new OwnerInvocationHandler(person));
}
PersonBean getNonOwnerProxy(PersonBean person) {
return (PersonBean) Proxy.newProxyInstance(person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
new NonOwnerInvocationHandler(person));
}
}
输出:
Name is: tim
Interests setfrom owner proxy
Can't setrating from owner proxy
Rating is 0
Name is: tim
Can't setinterests from non owner proxy
Rating setfrom non owner proxy
Rating is 1
分析:
需要实现InvocationHandler接口,然后会自动覆盖如下方法:
public Object invoke(Object proxy,Method method, Object[] args) throws IllegalAccessException
在实现类中需要传入需要代理的类字段
在invoke方法中进行调用。
返回该类的实例:
return (PersonBean) Proxy.newProxyInstance(person.getClass().getClassLoader(),
person.getClass().getInterfaces(),
new OwnerInvocationHandler(person));
本文通过一个具体的问题场景展示了如何利用JDK动态代理实现不同权限的访问控制。通过创建不同的InvocationHandler,使得Person类的拥有者和非拥有者具有不同的操作权限,如拥有者可以修改所有字段但不能给自己评分,非拥有者只能设置评分。通过Proxy.newProxyInstance创建代理对象,并在invoke方法中判断并执行相应操作。
23万+

被折叠的 条评论
为什么被折叠?



