aop底層是動態代理java
代理模型分析:spring
接口:express
//租房的接口:抽象 public interface Rent { //租房 void rent(); }
真實對象:apache
//房東的這個房子要出租 public class Host implements Rent {//房東實現rent接口 //出租 public void rent(){ System.out.println("host要出租房子"); } }
的代對象:編程
package com.david.staticproxy; //中介,即代理 public class Proxy implements Rent {//中介實現rent接口 //房東 private Host host; public void setHost(Host host) { this.host = host; } public void rent() { lookHouse();//看房方法 host.rent();//租房子方法 fare();//收費方法 } private void lookHouse(){ System.out.println("中介帶你看房"); } private void fare(){ System.out.println("收取中介費"); } }
測試:設計模式
public class You { public static void main(String[] args) { Host host = new Host(); Proxy proxy = new Proxy(); proxy.setHost(host); proxy.rent(); } }
因爲靜態代理開發效率低,因此咱們想須要一種可以有靜態代理的所有好處,可是又不存在這種缺點的東西。api
動態代理的角色和靜態代理的都同樣,可是動態代理是自動生成的。安全
動態代理分兩類:app
基於接口實現:jdkmaven
基於類實現:cglib
當今用的比較多的是Javassist來生成動態代理
動態代理相關類:
newProxyInstance(ClassLoader loader, 類<?>[] interfaces, InvocationHandler h)
返回指定接口的代理類的實例,該接口將方法調用分派給指定的調用處理程序代碼實現:
抽象角色
package com.li.daili.dao; public interface Rent { void rent(); }
真實角色
package com.li.daili.dao; public class Host implements Rent{ public void rent() { System.out.println("房東要租房"); } }
動態代理生成的接口對象
package com.li.daili.dao; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; public class InvocationHandlerProxy implements InvocationHandler { private Rent rent; public void setRent(Rent rent) { this.rent = rent; } public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this); } public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { lookHouse(); Object result = method.invoke(rent, args); takeMoney(); return result; } private void takeMoney() { System.out.println("收費"); } private void lookHouse() { System.out.println("看房"); } }
測試
package com.li.daili; import com.li.daili.dao.Host; import com.li.daili.dao.InvocationHandlerProxy; import com.li.daili.dao.Rent; public class TestDemo { public static void main(String[] args) { Host host = new Host(); InvocationHandlerProxy ihp = new InvocationHandlerProxy(); ihp.setRent(host); Rent proxy = (Rent) ihp.getProxy(); proxy.rent(); } }
動態代理的特色:
aop底層是動態代理
AOP是OOP的延續,是Aspect Oriented Programming的縮寫,意思是面向切面編程。能夠經過預編譯方式和運行期動態代理實現在不修改源代碼的狀況下給程序動態統一添加功能的一種技術。AOP實際是GoF設計模式的延續,設計模式追求的是調用者和被調用者之間的解耦,AOP能夠說也是這種目標的一種實現。
咱們如今作的一些非業務,如:日誌、事務、安全等都會寫在業務代碼中(也便是說,這些非業務類橫切於業務類),但這些代碼每每是重複的代碼,會給程序的維護帶來不便,AOP就實現了把這些業務需求與系統需求分開來作。這種解決的方式也稱代理機制。
編寫業務類
接口
package com.david.aop.service; public interface UserService { void add(); void delete(); void update(); void query(); }
實現類
package com.david.aop.service; public class UserServiceImpl implements UserService{ public void add() { System.out.println("添加一個用戶"); } public void delete() { System.out.println("刪除一個用戶"); } public void update() { System.out.println("更新一個用戶"); } public void query() { System.out.println("查詢一個用戶"); } }
定義日誌增長類實現
package com.david.aop.log; import org.springframework.aop.MethodBeforeAdvice; import java.lang.reflect.Method; public class Log implements MethodBeforeAdvice { public void before(Method method, Object[] objects, Object o) throws Throwable { System.out.println(o.getClass().getName()+"的"+method.getName()+"被執行了"); } }
package com.david.aop.log; import org.springframework.aop.AfterReturningAdvice; import java.lang.reflect.Method; public class AfterLog implements AfterReturningAdvice { public void afterReturning(Object returnValue, Method method, Object[] objects, Object target) throws Throwable { System.out.println("執行了"+target.getClass().getName() +"的"+method.getName()+"方法" +"返回值"+returnValue); } }
編寫spring核心配置文件applaction-config.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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userService" class="com.david.aop.service.UserServiceImpl"/> <bean id="log" class="com.david.aop.log.Log"/> <bean id="afterLog" class="com.david.aop.log.AfterLog"/> <aop:config> <aop:pointcut id="pointcut" expression="execution(* com.david.aop.service.UserServiceImpl.*(..))"/> <aop:advisor advice-ref="log" pointcut-ref="pointcut"/> <aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/> </aop:config> </beans>
測試類
package com.david.service; import com.david.aop.service.UserService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringAopTest { @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("application-config.xml"); UserService userService = (UserService) context.getBean("userService"); userService.add(); userService.update(); userService.query(); userService.delete(); } }
注意導入aop的織入包
<?xml version="1.0" encoding="UTF-8"?> <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"> <parent> <artifactId>springstudy</artifactId> <groupId>com.li</groupId> <version>1.0-SNAPSHOT</version> </parent> <modelVersion>4.0.0</modelVersion> <artifactId>springstudy03</artifactId> <dependencies> <dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.9</version> </dependency> </dependencies> </project>
運行結果:
com.david.aop.service.UserServiceImpl的add被執行了 添加一個用戶 執行了com.david.aop.service.UserServiceImpl的add方法返回值null com.david.aop.service.UserServiceImpl的update被執行了 更新一個用戶 執行了com.david.aop.service.UserServiceImpl的update方法返回值null com.david.aop.service.UserServiceImpl的query被執行了 查詢一個用戶 執行了com.david.aop.service.UserServiceImpl的query方法返回值null com.david.aop.service.UserServiceImpl的delete被執行了 刪除一個用戶 執行了com.david.aop.service.UserServiceImpl的delete方法返回值null
aop的思路很重要:橫向編程(改變原代碼,添加功能)。aop的本質仍是動態代理,在代碼中起到了解耦的做用
相對使用springAPI實現aop更簡單
真實對象和以前的同樣
自定一個Aop加強類:也就是所謂的切面
package com.david.aop.diy; public class Diy { public void before(){ System.out.println("===========before============"); } public void after(){ System.out.println("===========after============"); } }
注入bean,使用aop進行加強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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userService" class="com.david.aop.service.UserServiceImpl"/> <bean id="diy" class="com.david.aop.diy.Diy"/> <aop:config> <aop:aspect ref="diy"> <aop:pointcut id="diyPointcut" expression="execution(* com.david.aop.service.UserServiceImpl.*(..))"/> <aop:before method="before" pointcut-ref="diyPointcut"/> <aop:after method="after" pointcut-ref="diyPointcut"/> </aop:aspect> </aop:config> </beans>
測試類
package com.david.service; import com.david.aop.service.UserService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringAopTest { @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml"); UserService userService = (UserService) context.getBean("userService"); userService.add(); userService.update(); userService.query(); userService.delete(); } }
運行結果:
===========before============ 添加一個用戶 ===========after============ ===========before============ 更新一個用戶 ===========after============ ===========before============ 查詢一個用戶 ===========after============ ===========before============ 刪除一個用戶 ===========after============
@Aspect、@before、@after、@Around
目標對象不變
編寫加強的類,寫註解
類:
package com.david.aop.anno; import org.aspectj.lang.ProceedingJoinPoint; import org.aspectj.lang.annotation.*; @Aspect public class Anno { @Before("execution(* com.david.aop.service.UserServiceImpl.*(..))") public void before(){ System.out.println("===========方法執行前=========="); } @After("execution(* com.david.aop.service.UserServiceImpl.*(..))") public void after(){ System.out.println("==========執行方法後==========="); } @Around("execution(* com.david.aop.service.UserServiceImpl.*(..))") public void around(ProceedingJoinPoint joinPoint) throws Throwable { System.out.println("環繞前"); System.out.println("簽名"+joinPoint.getSignature()); Object proceed = joinPoint.proceed(); System.out.println("環繞後"); System.out.println(proceed); } }
配置文件:anno.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:aop="http://www.springframework.org/schema/aop" xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd"> <bean id="userService" class="com.david.aop.service.UserServiceImpl"/> <bean id="anno" class="com.david.aop.anno.Anno"/> <aop:aspectj-autoproxy/><!--自動代理--> </beans>
測試類:
package com.david.service; import com.david.aop.service.UserService; import org.junit.Test; import org.springframework.context.ApplicationContext; import org.springframework.context.support.ClassPathXmlApplicationContext; public class SpringAopTest { @Test public void test(){ ApplicationContext context = new ClassPathXmlApplicationContext("anno.xml"); UserService userService = (UserService) context.getBean("userService"); userService.add(); userService.update(); userService.query(); userService.delete(); } }
本質就是動態代理
須要到一個包,用來進行aop織入的包: aspectjweaver
打代碼的過程當中注意別遺漏了切面
三種實現AOP的方法