最近项目有个需求,要用到动态代理调用远程接口,本地不实现接口,然后就学习了一下该设计模式并记录下来。
我自己的理解。
代理:不提供对对象的直接引用,通过代理的方式对目标对象进行调用。我认为,目前最大的用处在于不改变原有实现类的源代码的情况下,扩展类,增加需求。比如,我的需求是这样的,我要增加对某个类的访问权限,而这个访问权限是针对某些类限定的,那么我就不能去直接更改这个目标类的源代码,因为一旦我再目标类里修改了源代码,那就意味着 所有访问此类的都要经过此权限校验,这与需求不符。那么我就可以使用代理,在需要调用此目标类的调用出使用代理类,在代理类中增加我们的权限验证,这样就需要修改原目标类的代码,又实现了功能。这只是我简单列举的其中一个例子,还有很多应用场景,比如 添加日志 等等
代理又分静态代理和动态代理
静态代理:针对每个需要被代理的类写一个代理类。缺点是:代理类和被代理类都要实现同一个接口或抽象类,并且,如果需要代理的类有很多的话,那么就需要写很多的代理类,因此,动态代理应运而生。
一、静态代理简单demo
1.公共接口(抽象类也行)
public interface UserService {
String getName(int id);
Integer getAge(int id);
}
2.实现类
public class UserServiceImpl implements UserService{
@Override
public String getName(int id) {
System.out.println("------getName-----");
return "我的name";
}
@Override
public Integer getAge(int id) {
System.out.println("---------getAge----------");
return 25;
}
}
3.代理类
public class UserServiceProxy implements UserService {
//目标类的引用
private UserService userService ;
public UserServiceProxy() {
this.userService = new UserServiceImpl();
}
public UserServiceProxy(UserService userService){
this.userService = userService;
}
@Override
public String doSometing(int id) {
//在调用目标类目标方法之前做一些其他操作,比如增加日志,权限什么的
//调用目标类的同一方法
String result = userService.doSometing(id);
//目标方法调用完成后做一些其他的操作,比如数据过滤,追加日志等
return result;
}
}
4.测试
public static void main(String[] args) {
// UserService userService = new UserServiceProxy();
UserService userService = new UserServiceProxy(new UserServiceImpl());
userService.doSometing(111);
}
5.结果
-------------------dosometing----------------:111
二、动态代理简单demo动态代理 ,代理类要实现invocationHandler接口,实现invoke方法即可,此方法是调用被代理类实际执行的方法
1.接口
public interface UserService {
String doSometing(int id);
String doSometing2(String name);
}
2.实现类
public class UserServiceImpl implements UserService{
@Override
public String doSometing(int id) {
System.out.println("-------------------dosometing----------------:" + id);
return String.valueOf(id);
}
@Override
public String doSometing2(String name) {
System.out.println("------------dosometing2-------------:" + name);
return name;
}
}
3.代理类
public class UserServiceHandler implements InvocationHandler {
//目标类的引用
private Object target ;
public UserServiceHandler(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用目标方法前做一些额外操作,比如日志,权限
//由于调用被代理的类的所有方法时都会进入到此方法中,所以,如果由于业务的需要,并不是所有方法都进行某些操作,那么也可以再次做判断
//比如,根据方法名判断 if(method.getName().equals("doSometing2")){做处理}
//调用被代理类的方法
Object result = method.invoke(target, args);
//调用完后做其他的处理,比如数据过滤啥的
return result;
}
}
4.测试
public static void main(String[] args) {
UserService userService = new UserServiceImpl();
InvocationHandler h = new UserServiceHandler(userService);
UserService userService2 = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), h);
userService2.doSometing2("haha");
userService2.doSometing(22);
}
5.结果
------------dosometing2-------------:haha
-------------------dosometing----------------:22
三、需求,不提供本地实现,只提供接口,用动态代理,使用httpclient远程调用
其实还是上面动态代理的升级版,只需要在调用出做一些修改即可。
1.接口
public interface UserService {
String doSometing(int id);
String doSometing2(String name);
}
2.代理类
public class UserServiceHandler implements InvocationHandler {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//调用目标方法前做一些额外操作,比如日志,权限
//由于没有实现类,所以不能调用metho.invoke方法,可以根据方法名做区分来判断具体执行的内容
Object result = null;
if(method.getName().equals("目标方法")){
//自己封装的httpclient的工具类
result = httpClientUtil.sendHttpPost(args);
}else{
//其他的。。。。。。。。。。
}
//调用完后做其他的处理,比如数据过滤啥的
return result;
}
}
3.工厂类 (这是我加了工厂,可用可不用)
public class ProxyBeanFactory {
@SuppressWarnings("unchecked")
public <T> T getProxy(Class<T> clazz) {
InvocationHandler handler = new UserServiceHandler();
return (T) Proxy.newProxyInstance(clazz.getClassLoader(), new Class[] { clazz }, handler);
}
}
4.测试
public static void main(String[] args) {
UserService proxy = (UserService) ProxyBeanFactory.getProxy(UserService.class);
proxy.doSometing2("haha");
}
基本的实现是这样的。