1. 程式人生 > >Spring動態代理的兩種方式

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(連接點)