23種設計模式——代理模式
阿新 • • 發佈:2021-07-30
相信大家都知道,有23種代理模式,其中用得比較多的或者是面試中估計問的最多的就是動態代理,但是我們知道,動態代理,靜態代理都只是23種設計模式中的代理模式。好了,話不多說,直接上乾貨。
代理模式
1、動態代理
先建立介面:
/** * 功能描述 * * @author yaoqihui * @version 2021/7/4 * @see [相關類/方法] * @since [malan-rabbitmq] */ public interface UserService { void saveUser(); }
寫一個類,實現介面:
import com.sailmalan.malan.service.UserService;import lombok.extern.slf4j.Slf4j; /** * 功能描述 * * @author yaoqihui * @version 2021/7/4 * @see [相關類/方法] * @since [malan-rabbitmq] */ @Slf4j public class UserServiceImpl implements UserService { @Override public void saveUser() { log.info("動態代理呼叫"); } }
建立代理類(可以重複利用)
import lombok.extern.slf4j.Slf4j;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
/**
* 動態代理類
*
* @author yaoqihui
* @version 2021/7/4
* @see [相關類/方法]
* @since [malan-rabbitmq]
*/
@Slf4j
public class InvocationHandlerImpl implements InvocationHandler {
private Object target;
public InvocationHandlerImpl(Object target) {
this.target = target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//method.invoke()方法,真正動態代理的地方,利用的是java的反射,大夥也可以看到包:java.lang.reflect.Method
return method.invoke(target, args);
}
}
動態代理測試類:
import com.sailmalan.malan.service.UserService; import com.sailmalan.malan.service.impl.UserServiceImpl; import java.lang.reflect.Proxy; /** * 功能描述:生成UserService,供呼叫---》類似於我們使用springBoot的註解,得到一個userService介面
@Autowired
private UserService userService; * * @author yaoqihui * @version2021/7/4 * @see [相關類/方法] * @since [malan-rabbitmq] */
public class TestInvocationHandler {
public static void main(String[] args) {
/************************類似於達到效果的註解:
* @Autowired
* private UserService userService;
* 開始程式碼**************************/
UserService userService = new UserServiceImpl();
InvocationHandlerImpl invocationHandler = new InvocationHandlerImpl(userService);
ClassLoader loader = userService.getClass().getClassLoader();
Class<?>[] interfaces = userService.getClass().getInterfaces();
UserService newProxyInstance = (UserService) Proxy.newProxyInstance(loader, interfaces, invocationHandler);
/************************結束程式碼**************************/
newProxyInstance.saveUser();
}
}
2、CGLIB靜態代理
- CGLIB動態代理和jdk代理一樣,使用反射完成代理,不同的是他可以直接代理類(jdk動態代理不行,他必須目標業務類必須實現介面),CGLIB動態代理底層使用位元組碼技術,CGLIB動態代理不能對 final類進行繼承。(CGLIB動態代理需要匯入jar包)
//介面 public interface UserDao { void save(); }
//介面實現類 public class UserDaoImpl implements UserDao { public void save() { System.out.println("儲存資料方法"); } }
代理類:
import org.springframework.cglib.proxy.Enhancer; import org.springframework.cglib.proxy.MethodInterceptor; import org.springframework.cglib.proxy.MethodProxy; import java.lang.reflect.Method; //代理主要類 public class CglibProxy implements MethodInterceptor { private Object targetObject; // 這裡的目標型別為Object,則可以接受任意一種引數作為被代理類,實現了動態代理 public Object getInstance(Object target) { // 設定需要建立子類的類 this.targetObject = target; Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(target.getClass()); enhancer.setCallback(this); return enhancer.create(); } //代理實際方法 public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy) throws Throwable { System.out.println("開啟事物"); Object result = proxy.invoke(targetObject, args); System.out.println("關閉事物"); // 返回代理物件 return result; } }
測試:
//測試CGLIB動態代理 public class Test { public static void main(String[] args) { CglibProxy cglibProxy = new CglibProxy(); UserDao userDao = (UserDao) cglibProxy.getInstance(new UserDaoImpl()); userDao.save(); } }
2、靜態代理程式碼演示
建立UserDao類:
//介面類 public class UserDao{ public void save() { System.out.println("儲存資料方法"); } }
新增代理類
//代理類 public class UserDaoProxy extends UserDao { private UserDao userDao; //此處是構造器注入 public UserDaoProxy(UserDao userDao) { this.userDao = userDao; } public void save() { System.out.println("開啟事物..."); userDao.save(); System.out.println("關閉事物..."); } }
下面測試靜態代理的類:
//新增完靜態代理的測試類 public class Test{ public static void main(String[] args) { UserDao userDao = new UserDao(); UserDaoProxy userDaoProxy = new UserDaoProxy(userDao); userDaoProxy.save(); } }