Spring動態代理的兩種方式
說明:spring AOP就是用aspectj來實現的,是依賴關係!AspectJ是動態代理的一種實現!而spring預設使用的就是AspectJ來實現的動態代理,spring自己的AOP就是使用AspectJ來實現的!當然你也可以使用其他的實現,如cglib!
第一種方式:利用JDK的反射機制(proxyJDK)
匯入aspectjrt.jar
aspectjwear.jar
package cn.xhx.jdkproxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; /** * 此攔截器為PersonDao加強功能(新增事務) * @author LenovoY510P * */ public class MyInterceptor implements InvocationHandler{ private Object target; private Transaction transaction; public MyInterceptor(Object target, Transaction transaction) { super(); this.target = target; this.transaction = transaction; } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { /** * 1、開啟事物 * 2、判斷方法名,執行方法 */ String methodName = method.getName(); if(methodName.equals("savePerson") || methodName.equals("deletePerson") || methodName.equals("updatePerson")) { transaction.beginTransaction(); method.invoke(target); transaction.commit(); } else { System.out.println("balabala..."); } return null; } }
package cn.xhx.jdkproxy;
public class PersonDaoImpl implements PersonDao {
public void savePerson() {
// TODO Auto-generated method stub
System.out.println("sava person()");
}
}
package cn.xhx.jdkproxy; import java.lang.reflect.Proxy; import org.junit.Test; public class ProxyJDKTest { @Test public void testJDKProxy() { Object target = new PersonDaoImpl(); Transaction transaction = new Transaction(); /** * 代理的三大引數 * 1、目標類的classLoader * 2、目標類的實現的所有介面的.class * 3、攔截器 */ MyInterceptor myInterceptor = new MyInterceptor(target, transaction); PersonDao personDao = (PersonDao)Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), myInterceptor); personDao.savePerson(); } }
package cn.xhx.jdkproxy;
public class Transaction {
public void beginTransaction() {
System.out.println("begin transaction");
}
public void commit() {
System.out.println("commit");
}
}
第二種方式:採用cglib
匯入cglib-nodep包
package cn.xhx.cglibproxy; import java.lang.reflect.Method; import net.sf.cglib.proxy.Enhancer; import net.sf.cglib.proxy.MethodInterceptor; import net.sf.cglib.proxy.MethodProxy; public class MyInterceptor implements MethodInterceptor{ private Object target; private Transaction transaction; public Object intercept(Object arg0, Method method, Object[] arg2, MethodProxy arg3) throws Throwable { transaction.beginTransaction();; method.invoke(target); transaction.commit(); return null; } public Object createProxy() { Enhancer enhancer = new Enhancer(); enhancer.setCallback(this); enhancer.setSuperclass(this.target.getClass()); return enhancer.create(); } public MyInterceptor(Object target, Transaction transaction) { super(); this.target = target; this.transaction = transaction; } }
package cn.xhx.cglibproxy;
import org.junit.Test;
public class CGLibProxyTest {
@Test
public void CGLibProxyTest() {
Object target = new PersonDao();
Transaction transaction = new Transaction();
MyInterceptor myInterceptor = new MyInterceptor(target, transaction);
PersonDao personDao = (PersonDao)myInterceptor.createProxy();
personDao.savaPerson();
}
}
package cn.xhx.cglibproxy;
public class PersonDao {
public void savaPerson() {
System.out.println("save person");
}
}
package cn.xhx.cglibproxy;
public class Transaction {
public void beginTransaction() {
System.out.println("begin transaction");
}
public void commit() {
System.out.println("commit");
}
}
總結
一個典型的動態代理建立物件過程可分為以下四個步驟:
1、通過實現InvocationHandler介面建立自己的呼叫處理器 IvocationHandler handler = new InvocationHandlerImpl(...);
2、通過為Proxy類指定ClassLoader物件和一組interface建立動態代理類
Class clazz = Proxy.getProxyClass(classLoader,new Class[]{...});
3、通過反射機制獲取動態代理類的建構函式,其引數型別是呼叫處理器介面型別
Constructor constructor = clazz.getConstructor(new Class[]{InvocationHandler.class});
4、通過建構函式建立代理類例項,此時需將呼叫處理器物件作為引數被傳入
Interface Proxy = (Interface)constructor.newInstance(new Object[] (handler));
為了簡化物件建立過程,Proxy類中的newInstance方法封裝了2~4,只需兩步即可完成代理物件的建立。
生成的ProxySubject繼承Proxy類實現Subject介面,實現的Subject的方法實際呼叫處理器的invoke方法,而invoke方法利用反射呼叫的是被代理物件的的方法(Object result=method.invoke(proxied,args))
美中不足
誠然,Proxy已經設計得非常優美,但是還是有一點點小小的遺憾之處,那就是它始終無法擺脫僅支援interface代理的桎梏,因為它的設計註定了這個遺憾。回想一下那些動態生成的代理類的繼承關係圖,它們已經註定有一個共同的父類叫Proxy。Java的繼承機制註定了這些動態代理類們無法實現對class的動態代理,原因是多繼承在Java中本質上就行不通。有很多條理由,人們可以否定對 class代理的必要性,但是同樣有一些理由,相信支援class動態代理會更美好。介面和類的劃分,本就不是很明顯,只是到了Java中才變得如此的細化。如果只從方法的宣告及是否被定義來考量,有一種兩者的混合體,它的名字叫抽象類。實現對抽象類的動態代理,相信也有其內在的價值。此外,還有一些歷史遺留的類,它們將因為沒有實現任何介面而從此與動態代理永世無緣。如此種種,不得不說是一個小小的遺憾。但是,不完美並不等於不偉大,偉大是一種本質,Java動態代理就是佐例。
相關推薦
動態代理 兩種方式
代理類Proxy和RealSubject應該實現了相同的功能介面,在面向物件的程式設計之中,如果想要兩個物件實現相同的功能,有以下兩種方式: 1) 定義一個功能介面,然後代理類Proxy和真實類
使用aspectJ實現Spring AOP的兩種方式
classpath .org 導入 ntc www. 之前 oid 方式 public 方式一:基於aspectJ的XML配置 方式二:基於aspectJ的註解方式 基於aspectJ的XML配置 1) 引入相關jar包 2) 創建Spr
使用web.xml方式載入Spring時,獲取Spring context的兩種方式
使用web.xml方式載入Spring時,獲取Spring context的兩種方式: 1、servlet方式載入時: 【web.xml】 <servlet> &nbs
spring 定時任務兩種方式
一 springMVC自帶task啟動後加載 上程式碼 首先新增依賴引入task <?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.o
MyBatis與Spring整合的兩種方式
1、第一步:匯入jar包 spring的jar包、Mybatis的jar包、Spring+mybatis的整合包、Mysql的資料庫驅動jar包、資料庫連線池的jar包 2、加入配置檔案: Spring的配置檔案——applicationContext.xml 這裡有一點
在Web應用中建立Spring容器的兩種方式
使用spring的web應用時,不用手動建立spring容器,而是通過配置檔案宣告式地建立spring容器,因此,在web應用中建立spring容器有如下兩種方式:一.直接在web.xml檔案中配置spring容器 二.利用第三方MVC框架的擴充套件點,建立spring容器
詳解SpringCloud-gateway動態路由兩種方式,以及路由載入過程
gateway配置路由主要有兩種方式,一種是用yml配置檔案,一種是寫程式碼裡,這兩種方式都是不支援動態配置的。如: 下面就來看看gateway是如何載入這些配置資訊的。 1 路由初始化 無論是yml還是程式碼,這些配置最終都是被封裝到RouteDefinition
spring注入bean兩種方式(屬性注入,構造器注入)
利用Spring的IOC實現簡單小程式,Spring推薦介面程式設計,這裡定義兩個介面:IDao,IService,以及它們的實現類IDaoImpl,IServiceImpl,程式碼如下: package DAO; public interface IDao {public
spring 配置的兩種方式:JAVA配置和註解配置
眾所周知,spring自從3.0開始以後,就全面推薦使用配置的方式進行程式碼編寫了,這種方式確實可以避免了之前一個專案裡面一大堆XML的情況,畢竟XML的可讀性實在不怎麼樣,而且一會寫JAVA,一會寫XML,確實還是蠻麻煩的 就目前來說spring的配置方式一
Spring容器的兩種方式詳解
1、Spring容器初始化兩種方式 (1)ApplicationContext(子類) //預設載入檔案系統的配置檔案,主要配置檔案放在專案下、本地上、類路徑下(3種位置) ApplicationContext ac=new FileSyst
Spring AOP 代理實現的兩種方式: JDK動態代理 和 Cglib框架動態代理
1.JDK動態代理 JDK API 內建 ---- 通過 Proxy類,為目標物件建立代理 (必須面向介面代理 ),此文中介面為UserDao,實現類為UserDaoImpl. public class UserDaoImpl implements UserDao {
Spring動態代理的兩種方式
說明:spring AOP就是用aspectj來實現的,是依賴關係!AspectJ是動態代理的一種實現!而spring預設使用的就是AspectJ來實現的動態代理,spring自己的AOP就是使用AspectJ來實現的!當然你也可以使用其他的實現,如cglib! 第一種方式
Spring中AOP實現的兩種方式之JDK和cglib的動態代理
AOP的實現原理: 都是基於代理模式,都是生成一個大代理物件 靜態AOP: AspectJ實現的AOP, 將切面程式碼直接編譯到Java類檔案中 --- 實現: JDK提供的動態代理技術 動態AOP: 將切面程式碼進行動態織入實現的AOP --- Spring的AOP為動態
動態代理的兩種方式以及區別
動態代理的兩種方式,以及區別。 JDK動態代理:利用反射機制生成一個實現代理介面的匿名類,在呼叫具體方法前呼叫InvokeHandler來處理。 CGlib動態代理:利用ASM(開源的Java位元組碼編
MyBatis開發Dao層的兩種方式(Mapper動態代理方式)
MyBatis開發原始Dao層請閱讀我的上一篇部落格:MyBatis開發Dao層的兩種方式(原始Dao層開發) 接上一篇部落格繼續介紹MyBatis開發Dao層的第二種方式:Mapper動態代理方式 Mapper介面開發方法只需要程式設計師編寫Mapper介面(相當於Dao介面),由Mybat
使用JDK和Cglib兩種方式動態代理
一 使用JDK動態代理這種方式,只能對介面進行動態代理,有一定的侷限性;介面:package org.spring.test2; import java.util.Map; public interface UserService { void insert(Map&l
Spring AOP的兩種代理方式
Spring AOP是通過為目標物件建立代理來實現的。其使用的代理方式有兩種: JDK 動態代理 (目標物件實現了介面時使用,只會代理目標介面方法) CGLIB (當目標物件沒有實現介面時只能使用CGLIB ,當然可以通過配置強制有介面的物件也使用CGLIB
Spring中使用屬性文件properties的兩種方式
文件 location 郵件發送 class mave red onf 路徑 文件內容 實際項目中,通常將可配置的參數放到屬性文件中,例如數據庫連接信息、redis連接信息等,便於統一管理。然後通過IoC框架spring將其加載到上下文中,使得程序可以直接使用。 創建mys
spring boot返回Josn的兩種方式
pre ges 取數據 獲取數據 路徑 spring wid tco resp [email protected]/* */ [email protected]/* */,[email protected]/* */ @[emai
Spring系列之AOP實現的兩種方式
部分 靜態常量 cep value conf tar import enc ble AOP常用的實現方式有兩種,一種是采用聲明的方式來實現(基於XML),一種是采用註解的方式來實現(基於AspectJ)。 首先復習下AOP中一些比較重要的概念: Joinpoint(連接點)