代理模式,静态、动态代理的实践
静态代理
静态代理实现步骤:
- 定义一个接口及其实现类;
- 创建一个代理类同样实现这个接口
- 将目标对象注入进代理类,然后在代理类的对应方法调用目标类中的对应方法。这样的话,我们就可以通过代理类屏蔽对目标对象的访问,并且可以在目标方法执行前后做一些自己想做的事情。
代码实现:
1、定义一个短信功能接口
public interface SmsService {
String send(String message);
}
2、实现这个短信接口
public class SmsServiceImpl implements SmsService {
public String send(String message) {
System.out.println("send message:" + message);
return message;
}
}
3、创建代理类,并实现短信接口
public class SmsProxy implements SmsService {
// 实际被代理对象
private final SmsService smsService;
public SmsProxy(SmsService smsService) {
this.smsService = smsService;
}
@Override
public String send(String message) {
//调用方法之前,我们可以添加自己的操作
System.out.println("before method send()");
smsService.send(message);
//调用方法之后,我们同样可以添加自己的操作
System.out.println("after method send()");
return null;
}
}
4、使用
public class Main {
public static void main(String[] args) {
SmsService smsService = new SmsServiceImpl();
SmsProxy smsProxy = new SmsProxy(smsService);
smsProxy.send("java");
}
}
动态代理
JDK 动态代理实现步骤
- 定义一个接口及其实现类;
- 自定义 InvocationHandler 并重写 invoke 方法,在 invoke 方法中我们会调用原生方法(被代理类的方法)并自定义一些处理逻辑;
- 通过 Proxy.newProxyInstance (ClassLoader loader,Class<?>[] interfaces,InvocationHandler h) 方法创建代理对象;
动态代理案例一
创建功能接口
public interface Human{
void eat();
void run();
void walk();
}
创建被代理类,并实现功能类
class SuperMan implements Human{
@Override
public void eat(){
System.out.println("超人不需要吃饭,需要太阳能!");
}
@Override
public void run(){
System.out.println("超人飞行速度为300km/h");
}
@Override
public void walk(){
System.out.println("超人的走路速度为90km/h");
}
}
创建代理类并实现接口 InvocationHandler
重写里面的 invoke 方法
class MyInvocationHandler implements InvocationHandler{
Object obj;
// 实现被调用对象绑定
public void bind(Object obj){
this.obj = obj;
}
// 当通过代理类的对象,调用方法a时,就会自动调用如下方法
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{ //obj被代理类对象
// 实现被代理类的方法调用逻辑
// 该返回值作为当前类中的invoke()的返回值
Object invoke = method.invoke(obj, args);
return invoke;
}
}
创建用于返回代理类对象的代理工厂
class ProxyFactory{
// 创建一个静态方法 返回一个代理类对象
public static Object getProxyInstance(Object obj){ //obj 被代理对象
MyInvocationHandler handler = new MyInvocationHandler();
// 进行绑定(绑定代理类和被代理对象)
handler.bind(obj);
// 通过类加载器获取被代理类的对象
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), handler);
}
}
测试
public class proxyTest{
public static void main(String[] args){
// 创建被代理类对象
SuperMan superMan = new SuperMan();
// 创建代理类对象--通过静态方法直接获取
Human proxyInstance = (Human) ProxyFactory.getProxyInstance(superMan);
// 通过代理类对象调用方法
proxyInstance.eat();
proxyInstance.run();
proxyInstance.walk();
}
}
动态代理案例二
UserDAOImpl 实现 UserDAO 接口,UserDAOImpl 需要增加功能,使用代理对象的方法
利用 Proxy 代理类的静态方法 newProxyInstance() 创建被代理类的对象;
静态方法中的三个参数分别为: 类加载器、要实现功能修改的类的接口的数组(可以是多个接口)、 InvocationHandler 接口的实现类对象(匿名内部类、实现类对象)
在实现类或者匿名内部类中实现重写 invoke() 方法,在 invoke 方法中实现对功能的增强代码如下面的实现类中
定义一个功能接口
UserDao.java
public interface UserDAO {
public abstract int add(int a,int b);
public abstract String update(String id);
}
定义功能接口的实现类
UserDAOImpl.java
public class UserDAOImpl implements UserDAO{
@Override
public int add(int a, int b) {
System.out.println("add() executing...");
return a + b;
}
@Override
public String update(String id) {
System.out.println("update executing...");
return id + ":update";
}
}
创建代理对象类
public class MyProxy {
public static void main(String[] args) {
// 匿名实现类方式
// UserDAO userDAO = (UserDAO) Proxy.newProxyInstance(MyProxy.class.getClassLoader(), interfaces, new InvocationHandler() {
// @Override
// public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// return null;
// }
// });
Class [] interfaces = {UserDAO.class};
UserDAOImpl userDAOImpl = new UserDAOImpl();
UserDAO userDAO = (UserDAO) Proxy.newProxyInstance(MyProxy.class.getClassLoader(), interfaces, new UserDAOProxy(userDAOImpl));
int result = userDAO.add(1, 2);
System.out.println(result);
System.out.println(userDAO.update("5"));
}
}
// 创建代理类
class UserDAOProxy implements InvocationHandler {
//利用有参构造的方式,对obj进行初始化(需要那个代理对象被创建,就把哪个对象传进来) 对应上边第三个参数
private Object obj;
public UserDAOProxy(Object obj) {
this.obj = obj;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//在方法执行之前
System.out.println("在需要更新的方法之前执行: " + method.getName());
//方法调用
Object res = method.invoke(obj, args);
//在方法执行之后
System.out.println("在需要更新的方法之后: ");
return res;
}
}
参考文章:
- https://snailclimb.gitee.io/javaguide/#/docs/java/basis/%E4%BB%A3%E7%90%86%E6%A8%A1%E5%BC%8F%E8%AF%A6%E8%A7%A3?id=_1-%e4%bb%a3%e7%90%86%e6%a8%a1%e5%bc%8f
- https://www.liaoxuefeng.com/wiki/1252599548343744/1264804593397984