(转)java动态代理与aop
轉(zhuǎn)自: Java 動(dòng)態(tài)代理與AOP - 如果的事 - 博客園動(dòng)態(tài)代理與AOP 代理模式 代理模式給某一個(gè)目標(biāo)對(duì)象(target)提供代理對(duì)象(proxy),并由代理對(duì)象控制對(duì)target對(duì)象的引用。 模式圖: 代理模式中的角色有: 抽象對(duì)象角色(Abstrachttps://www.cnblogs.com/chenny7/p/11201010.html
【1】代理模式
/*** 抽象對(duì)象角色*/ abstract class AbstractObject {public abstract void operation(); } /*** 目標(biāo)對(duì)象*/ class TargetObject extends AbstractObject {public void operation() {System.out.println("Do Something!");} } /*** 代理對(duì)象*/ public class ProxyObject extends AbstractObject {TargetObject targetObject = new TargetObject();@Overridepublic void operation() {System.out.println("do sth before");targetObject.operation();System.out.println("do sth after");}public static void main(String[] args) {new ProxyObject().operation();} }代理模式中的角色有:
- 抽象對(duì)象角色(AbstractObject):聲明了目標(biāo)對(duì)象和代理對(duì)象的共同接口,這樣依賴在任何可以使用目標(biāo)對(duì)象的地方都可以使用代理對(duì)象。
- 目標(biāo)對(duì)象角色(RealObject):定義了代理對(duì)象所代表的目標(biāo)對(duì)象。???
- 代理對(duì)象角色(ProxyObject):代理對(duì)象內(nèi)部含有目標(biāo)對(duì)象的引用,從而可以在任何時(shí)候操作目標(biāo)對(duì)象;代理對(duì)象提供一個(gè)與目標(biāo)對(duì)象相同的接口,以便可以在任何時(shí)候替代目標(biāo)對(duì)象。代理對(duì)象通常在客戶端調(diào)用傳遞給目標(biāo)對(duì)象之前或者之后,執(zhí)行某個(gè)操作,而不是單純的將調(diào)用傳遞給目標(biāo)對(duì)象。
【2】靜態(tài)代理與動(dòng)態(tài)代理
按照代理類的創(chuàng)建時(shí)期,可分為靜態(tài)代理和動(dòng)態(tài)代理:
- 靜態(tài)代理:由程序員創(chuàng)建代理類或特定工具自動(dòng)生成源代碼再對(duì)其編譯。在程序運(yùn)行前代理類的.class文件就已經(jīng)存在了。
- 動(dòng)態(tài)代理:在程序運(yùn)行時(shí)運(yùn)用反射機(jī)制動(dòng)態(tài)創(chuàng)建而成。
【2.1】靜態(tài)代理
/*** 會(huì)飛接口*/ interface Flyable {void fly(long ms); } /*** 會(huì)飛的鳥(niǎo)*/ class Bird implements Flyable {@Overridepublic void fly(long ms) {System.out.println("bird is flying.");try {Thread.sleep(ms);} catch (Exception e ) {System.out.println("bird睡眠異常");}} } /*** 會(huì)飛的風(fēng)箏*/ class Kite implements Flyable {@Overridepublic void fly(long ms) {System.out.println("kite is flying.");try {Thread.sleep(ms);} catch (Exception e ) {System.out.println("kite 睡眠異常");}} } /*** 靜態(tài)代理*/ public class StaticProxy implements Flyable {private Flyable flyable;public StaticProxy(Flyable flyable) {this.flyable = flyable;}@Overridepublic void fly(long ms) {System.out.println("before fly");flyable.fly(ms);System.out.println("after fly");}public static void main(String[] args) {new StaticProxy(new Kite()).fly(1000);new StaticProxy(new Bird()).fly(1000);} }靜態(tài)代理缺點(diǎn):
- 若接口? Flyable 增加一個(gè)方法,則目標(biāo)對(duì)象(接口實(shí)現(xiàn)類)與代理類全都需要增加方法實(shí)現(xiàn),全都需要修改代碼;
【2.2】動(dòng)態(tài)代理
/*** 動(dòng)態(tài)代理*/ public class DynamicProxy implements InvocationHandler {private Object targetObject;public Object newProxyInstance(Object targetObject) {this.targetObject = targetObject;return Proxy.newProxyInstance(targetObject.getClass().getClassLoader(), targetObject.getClass().getInterfaces(), this);}@Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {System.out.println("before invoke");proxy = method.invoke(targetObject, args);System.out.println("before after");return proxy;}public static void main(String[] args) {DynamicProxy dProxy = new DynamicProxy();// 會(huì)飛的鳥(niǎo)Flyable bird = (Flyable)dProxy.newProxyInstance(new Bird());bird.fly(1000);// 風(fēng)箏Flyable kite = (Flyable)dProxy.newProxyInstance(new Kite());kite.fly(1000);} }顯然, 動(dòng)態(tài)代理對(duì)象不需要實(shí)現(xiàn)目標(biāo)對(duì)象接口,但目標(biāo)對(duì)象一定要實(shí)現(xiàn)接口,否則不能使用代理;
【3】cglib 代理
1)應(yīng)用場(chǎng)景:
- 有的時(shí)候,目標(biāo)對(duì)象可能只是一個(gè)單獨(dú)的對(duì)象,并沒(méi)有實(shí)現(xiàn)任何的接口,這個(gè)時(shí)候,我們就可以使用目標(biāo)對(duì)象子類的方式實(shí)現(xiàn)代理,這種代理方式就是:Cglib代理,也叫做子類代理,它是在內(nèi)存中構(gòu)件一個(gè)子類對(duì)象,從而實(shí)現(xiàn)對(duì)目標(biāo)對(duì)象的功能拓展。
2)cglib 介紹
- Cglib是強(qiáng)大的高性能的代碼生成包,它可以在運(yùn)行期間拓展Java類與實(shí)現(xiàn)Java接口。它廣泛的被許多AOP的框架使用,例如Spring AOP和synaop,為他們提供方法的interception(攔截)。
- Cglib包的底層是通過(guò)使用一個(gè)小而快的字節(jié)碼處理框架ASM來(lái)轉(zhuǎn)換字節(jié)碼并生成新的類,不鼓勵(lì)直接只使用ASM,因?yàn)樗竽惚仨殞?duì)JVM內(nèi)部結(jié)構(gòu),包括class文件的格式和指令集都很熟悉。
maven pom.xml?
<!-- https://mvnrepository.com/artifact/cglib/cglib --><dependency><groupId>cglib</groupId><artifactId>cglib</artifactId><version>3.3.0</version></dependency>【4】 spring aop
1)Spring在新版本中對(duì)AOP功能進(jìn)行了增強(qiáng),體現(xiàn)在這么幾個(gè)方面:
- ??? 在XML配置文件中為AOP提供了aop命名空間
- ??? 增加了AspectJ切點(diǎn)表達(dá)式語(yǔ)言的支持
- ??? 可以無(wú)縫地集成AspectJ
2)如何使用 引介切面(Introduction Advisor)為一個(gè)現(xiàn)有對(duì)象添加任何接口的實(shí)現(xiàn):
2.1)定義兩個(gè)接口及其實(shí)現(xiàn)類,包括 服務(wù)員與售貨員;
public class SpringAopDef { } interface Waiter { // 服務(wù)員接口void greetTo(String client);void serveTo(String client); } class NaiveWaiter implements Waiter { // 服務(wù)員實(shí)現(xiàn)類public void greetTo(String client) {System.out.println("NaiveWaiter greet to " + client);}public void serveTo(String client) {System.out.println("NaiveWaiter serve to " + client);} } interface Seller {// 售貨員接口int sell(String goods, String client); } class SmartSeller implements Seller { // 售貨員實(shí)現(xiàn)類public int sell(String goods, String client) {System.out.println("a smart seller sells " + goods + " to " + client);return 100;} }2.2)下一步,我們想讓 服務(wù)員充當(dāng)售貨員角色,可以賣東西;
引入切面:
@Aspect public class EnableSellerAspect {@DeclareParents(value="com.swjtu.mybatis.proxy.springaop.NaiveWaiter" // 切點(diǎn)-目標(biāo)類, defaultImpl = SmartSeller.class) // 增強(qiáng)類public Seller seller; // 增強(qiáng)類接口 }maven pom 引入spring依賴
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>com.swjtu.mybatis</groupId><artifactId>MybatisHello2</artifactId><version>0.0.1-SNAPSHOT</version><properties><spring.version>5.2.0.RELEASE</spring.version></properties> ................. <dependencies><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId><version>1.9.4</version></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjweaver</artifactId><version>1.9.4</version></dependency><!-- Spring Dependencies --><dependency><groupId>org.springframework</groupId><artifactId>spring-core</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-beans</artifactId><version>${spring.version}</version></dependency><dependency><groupId>org.springframework</groupId><artifactId>spring-context</artifactId><version>${spring.version}</version></dependency></dependencies>beans.xml 如下:
<?xml version="1.0" encoding="UTF-8"?> <beans xmlns="http://www.springframework.org/schema/beans"xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xmlns:context="http://www.springframework.org/schema/context"xmlns:aop="http://www.springframework.org/schema/aop"xsi:schemaLocation="http://www.springframework.org/schema/beanshttp://www.springframework.org/schema/beans/spring-beans.xsdhttp://www.springframework.org/schema/aophttp://www.springframework.org/schema/aop/spring-aop-4.0.xsdhttp://www.springframework.org/schema/context/http://www.springframework.org/schema/context/spring-context.xsd"><aop:aspectj-autoproxy/><bean id="waiter" class="com.swjtu.mybatis.proxy.springaop.NaiveWaiter"/><bean class="com.swjtu.mybatis.proxy.springaop.EnableSellerAspect"/><!-- 定義切面 --><bean id="testBeforeAdvice" class="com.swjtu.mybatis.proxy.springaop.advice.TestBeforeAdvice"/><aop:config proxy-target-class="true"><aop:advisor advice-ref="testBeforeAdvice" pointcut="execution(* com..*.Waiter.greetTo(..))"/></aop:config></beans>切面如下:
public class TestBeforeAdvice implements MethodBeforeAdvice {@Overridepublic void before(Method method, Object[] objects, Object o) throws Throwable {System.out.println("before invoke");System.out.println("do busi");System.out.println("after invoke");} }當(dāng)調(diào)用 Waiter.greetTo() 方法會(huì)調(diào)用 before 通知;
springaop 測(cè)試用例入口:
public class SpringAopMain {public static void main(String[] args) {// 獲取上下文環(huán)境ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");Waiter waiter = (Waiter)context.getBean("waiter"); // 從上下文中獲取bean// 調(diào)用服務(wù)員原有方法waiter.greetTo("zhangsan");waiter.serveTo("zhangsan");// 通過(guò)切面已經(jīng)將 Waiter 實(shí)現(xiàn)了 Seller 接口,所以可以強(qiáng)制轉(zhuǎn)換Seller seller = (Seller) waiter;seller.sell("apple", "zhangsan");} } // spring aop 打印日志 before invoke do busi after invoke NaiveWaiter greet to zhangsan NaiveWaiter serve to zhangsan a smart seller sells apple to zhangsan 創(chuàng)作挑戰(zhàn)賽新人創(chuàng)作獎(jiǎng)勵(lì)來(lái)咯,堅(jiān)持創(chuàng)作打卡瓜分現(xiàn)金大獎(jiǎng)總結(jié)
以上是生活随笔為你收集整理的(转)java动态代理与aop的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 应用程序无法正常启动0xc000007b
- 下一篇: (转)使用IDEA将普通MAVEN项目转