Spring中的代理模式(jdk為主)
代理的分類:靜態代理 動態代理(jdk動態代理/cglib動態代理)
-
- 靜態代理:
描述:有多個業務類,就有多少個代理類,代理類,在編譯之前就已經存在了,和業務類同時存在。
靜態代理:
1、需要知道核心類(被代理類)是哪一個類,並且有什麼方法。
2、非核心的程式碼需要重複寫多次,顯得程式碼的結構臃腫,形成程式碼冗餘。
3、非核心類(代理類)需要實現核心類(被代理類)實現的介面,也就是他們需要實現共同的介面,但是以核心類實現的介面(被代理類)為準。
l目地是將業務程式碼與日誌程式碼完全分離,實現鬆散耦合.
l代理物件與被代理物件必須實現同一介面,在代理物件中實現與日誌記錄的相關服務
靜態代理的弊端:
一個代理介面只能服務於一種型別的物件.對於稍大點的專案根本無法勝任.
靜態代理的實現:
1、先確定核心類(被代理的類)。
其中的方法:
@Resource
private UserDao userDao;
public void inserts(User user) throws SQLException {
userDao.insert(user);
SpringCha springCha = new SpringCha();
springCha.setHabit("先吃再睡");
springCha.setHobby("吃喝睡
userDao.insert(springCha);
}2、在去編寫非核心類。
事務處理:
@Resource
private TManager tManager;
@Resource
private UserServiceImpl1 userServiceImpl1;
public void inserts(User user) throws SQLException {
try {
tManager.closeCommit();
userServiceImpl1.inserts(user);
tManager.commit();
} catch (SQLException e) {
e.printStackTrace();
tManager.rollBack();
}
}3、在使用非核心類。
-
動態代理(jdk):
- 利用靜態代理中的核心類(這個核心類是靜態和動態所需的)
- 在建立一個類(xxxProxy)來實現InvocationHandler介面
- 在實現InvocationHandler後,進行編寫裡面的方法
//使用註解把實現動態代理的類注入spring容器中
@Component
public class Dynamic implements InvocationHandler {
@Resource(name = "userServiceImpl1")
private Object object;
/**
* 用來在測試類中進行測試時獲取例項,以及介面
* UserService o = (UserService)Proxy.newProxyInstance(
* dynamic.getObject().getClass().getClassLoader(),
* dynamic.getObject().getClass().getInterfaces(),
* dynamic);
* @return
*//**
* 當用戶呼叫物件中的每個方法時都通過下面的方法執行,方法必須在介面
* proxy 被代理後的物件
* method 將要被執行的方法資訊(反射)
* args 執行方法時需要的引數
*/
public Object getObject() {
return object;
}
/**
* 事務處理,來處理後續資料庫操作可能出現的錯誤
*/
@Resource
private TManager tManager;
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object invoke=null;
try {
// 關閉自動提交事務
tManager.closeCommit();
// 返回我們需要動態代理的實現類
invoke= method.invoke(object, args);
// 手動提交事務
tManager.commit();
} catch (SQLException e) {
e.printStackTrace();
// 事務回滾
tManager.rollBack();
}
return invoke;
}
}- 在使用(在測試中使用)
/**
* 動態代理
*/
@Resource
private Dynamic dynamic;
@Test
public void testInsert2() throws SQLException {// 在使用動態代理,在返回實現類但是需要使用它的介面
/**
* 通過Proxy的newProxyInstance方法來建立我們的代理物件,我們來看看其三個引數
* 第一個引數 dynamic.getObject().getClass().getClassLoader(),我們這裡使用handler這個類的ClassLoader物件來載入我們的代理物件
* 第二個引數dynamic.getObject().getClass().getInterfaces(),是為代理物件提供的介面是真實物件所實行的介面,表示我要代理的是該真實物件,這樣我就能呼叫這組介面中的方法了
* 第三個引數dynamic,將這個代理物件關聯到了上方的 InvocationHandler 這個物件上
*/
UserService o = (UserService)Proxy.newProxyInstance(
dynamic.getObject().getClass().getClassLoader(),
dynamic.getObject().getClass().getInterfaces(),
dynamic);
User user = new User();
user.setName("楓");
user.setPassword("201619");
o.inserts(user);
}並且在使用實現動態代理有一個問題:被代理的類必須實現介面,未實現介面則沒辦法完成動態代理。而且在動態代理類中也是隻能去處理一個被代理類。