1. cglib概述: java
code Generation Libary (cglib) ,是一個強大的、高性能、高質量的COde生成類庫。它能夠在運行期擴展Java類與實現Java接口。 spring
cglib封裝了asm,能夠在運行期動態生成新的class。 框架
cglib用於AOP,JDK中的proxy必須基於接口,cglib沒有這個限制 ide
cglib應用: 函數
以一個實例在簡單介紹下cglib的應用。
咱們模擬一個虛擬的場景,關於信息的管理。
1)原始需求是任何人能夠操做信息的create,update,delete,query操做。
InfoManager.java--封裝對信息的操做
性能
public
class InfoManager {
//
模擬查詢操做
public
void query() {
System.out.println("query");
}
//
模擬建立操做
public
void create() {
System.out.println("create");
}
//
模擬更新操做
public
void update() {
System.out.println("update");
}
//
模擬刪除操做
public
void delete() {
System.out.println("delete");
}
}
InfoManagerFactory.java
--工廠類
public
class InfoManagerFactory {
private
static InfoManager manger =
new InfoManager();
/**
* 建立原始的InfoManager
*
*
@return
*/
public
static InfoManager getInstance() {
return manger;
}
}
client.java
--供客戶端調用
public
class Client {
public
static
void main(String[] args) {
Client c =
new Client();
c.anyonecanManager();
}
/**
* 模擬:沒有任何權限要求,任何人均可以操做
*/
public
void anyonecanManager() {
System.out.println("any one can do manager");
InfoManager manager = InfoManagerFactory.getInstance();
doCRUD(manager);
separatorLine();
}
/**
* 對Info作增長/更新/刪除/查詢操做
*
*
@param
manager
*/
private
void doCRUD(InfoManager manager) {
manager.create();
manager.update();
manager.delete();
manager.query();
}
/**
* 加一個分隔行,用於區分
*/
private
void separatorLine() {
System.out.println("################################");
}
}
至此,沒有涉及到cglib的內容,由於需求太簡單了,可是接下來,需求發生了改變,要求:
2)只有一個叫「maurice」的用戶登陸,才容許對信息進行create,update,delete,query的操做。
怎麼辦?難道在每一個方法前,都加上一個權限判斷嗎?這樣重複邏輯太多了,因而乎想到了Proxy(代理模式),可是原先的InfoManager也沒有實現接口,不能採用jdk的proxy。那麼cglib在這邊就要隆重登場。
一旦使用cgblig,只須要添加一個MethodInterceptor的類以及修改factory代碼就能夠實現這個需求。
AuthProxy.java
--權限校驗代理類
public
class AuthProxy
implements MethodInterceptor {
private String name;
//
會員登陸名
public AuthProxy(String name) {
this.name = name;
}
/**
* 權限校驗,若是會員名爲:maurice,則有權限作操做,不然提示沒有權限
*/
@Override
public Object intercept(Object obj, Method method, Object[] args, MethodProxy proxy)
throws Throwable {
if (!"maurice".equals(
this.name)) {
System.out.println("AuthProxy:you have no permits to do manager!");
return
null;
}
return proxy.invokeSuper(obj, args);
}
public String getName() {
return name;
}
public
void setName(String name) {
this.name = name;
}
}
InfoManagerFactory.java
--代碼變更以下:
public
class InfoManagerFactory {
/**
* 建立帶有權限檢驗的InfoManager
*
*
@param
auth
*
@return
*/
public
static InfoManager getAuthInstance(AuthProxy auth) {
Enhancer enhancer =
new Enhancer();
enhancer.setSuperclass(InfoManager.
class);
enhancer.setCallback(auth);
return (InfoManager) enhancer.create();
}
}
client.java
--代碼修改以下
public
class Client {
public
static
void main(String[] args) {
Client c =
new Client();
c.haveNoAuthManager();
c.haveAuthManager();
}
/**
* 模擬:登陸會員沒有權限
*/
public
void haveNoAuthManager() {
System.out.println("the loginer's name is not maurice,so have no permits do manager
");
InfoManager noAuthManager = InfoManagerFactory.getAuthInstance(
new AuthProxy("maurice1"));
doCRUD(noAuthManager);
separatorLine();
}
/**
* 模擬:登陸會員有權限
*/
public
void haveAuthManager() {
System.out.println("the loginer's name is maurice,so have permits do manager
");
InfoManager authManager = InfoManagerFactory.getAuthInstance(
new AuthProxy("maurice"));
doCRUD(authManager);
separatorLine();
}
/**
* 對Info作增長/更新/刪除/查詢操做
*
*
@param
manager
*/
private
void doCRUD(InfoManager manager) {
manager.create();
manager.update();
manager.delete();
manager.query();
}
/**
* 加一個分隔行,用於區分
*/
private
void separatorLine() {
System.out.println("################################");
}
}
執行下代碼,發現這時client端中已經加上了權限校驗。
一樣是InfoManager,爲何這時能多了權限的判斷呢?Factory中
enhancer.create()返回的究竟是什麼對象呢?這個疑問將在第三部分CGlib中解釋。
這邊的代碼,實際上是介紹了cglib中的enhancer功能.
到這裏,參照上面的代碼,就可使用cglib帶來的aop功能了。可是爲了更多介紹下cglib的功能,模擬需求再次發生變化:
3)因爲query功能用戶maurice才能使用,招來其餘用戶的強烈的抱怨,因此權限再次變動,只有create,update,delete,才須要權限保護,query任何人均可以使用。
怎麼辦?採用AuthProxy,使得InfoManager中的全部方法都被代理,加上了權限的判斷。固然,最容易想到的辦法,就是在AuthProxy的intercept的方法中再作下判斷,若是代理的method是query,不須要權限驗證。這麼作,能夠,可是一旦邏輯比較複雜的時候,intercept這個方法要作的事情會不少,邏輯會異常的複雜。
幸虧,cglib還提供了CallbackFilter。使用CallbackFilter,能夠明確代表,被代理的類(InfoManager)中不一樣的方法,被哪一個攔截器(interceptor)攔截。
AuthProxyFilter.java
public
class AuthProxyFilter
implements CallbackFilter {
private
static
final
int AUTH_NEED = 0;
private
static
final
int AUTH_NOT_NEED = 1;
/**
* <pre>
* 選擇使用的proxy
* 若是調用query函數,則使用第二個proxy
* 不然,使用第一個proxy
* </pre>
*/
@Override
public
int accept(Method method) {
if ("query".equals(method.getName())) {
return AUTH_NOT_NEED;
}
return AUTH_NEED;
}
}
這段代碼什麼意思?其中的accept方法的意思是說,若是代理的方法是query(),那麼使用第二個攔截器去攔截,若是代理的方法不是query(),那麼使用第一個攔截器去攔截。因此咱們只要再寫一個攔截器,不作權限校驗就好了。(其實,cglib中的NoOp.INSTANCE就是一個空的攔截器,只要配置上這個就能夠了。)
InfoManagerFactory.java
--代碼修改以下:(配置不一樣的攔截器和filter)
public
class InfoManagerFactory {
/**
* 建立不一樣權限要求的InfoManager
*
*
@param
auth
*
@return
*/
public
static InfoManager getSelectivityAuthInstance(AuthProxy auth) {
Enhancer enhancer =
new Enhancer();
enhancer.setSuperclass(InfoManager.
class);
enhancer.setCallbacks(
new Callback[] { auth, NoOp.INSTANCE });
enhancer.setCallbackFilter(
new AuthProxyFilter());
return (InfoManager) enhancer.create();
}
}
記住:setCallbacks中的攔截器(interceptor)的順序,必定要和
CallbackFilter裏面指定的順序一致!!切忌。
Client.java
public
class Client {
public
static
void main(String[] args) {
Client c =
new Client();
c.selectivityAuthManager();
}
/**
* 模擬:沒有權限的會員,能夠做查詢操做
*/
public
void selectivityAuthManager() {
System.out.println("the loginer's name is not maurice,so have no permits do manager except do query operator
");
InfoManager authManager = InfoManagerFactory.getSelectivityAuthInstance(
new AuthProxy("maurice1"));
doCRUD(authManager);
separatorLine();
}
/**
* 對Info作增長/更新/刪除/查詢操做
*
*
@param
manager
*/
private
void doCRUD(InfoManager manager) {
manager.create();
manager.update();
manager.delete();
manager.query();
}
/**
* 加一個分隔行,用於區分
*/
private
void separatorLine() {
System.out.println("################################");
}
}
此時,對於query的權限校驗已經被去掉了。
經過一個模擬需求,簡單介紹了cglib aop功能的使用。
CGlib應用很是廣,在spring,hibernate等框架中,被大量的使用。