javascript
08 Spring框架 AOP (一)
首先我們先來介紹一下AOP:?
AOP(Aspect Orient Programming),面向切面編程,是面向對象編程OOP的一種補充。
面向對象編程是從靜態角度考慮程序的結構,面向切面編程是從動態的角度考慮程序運行過程。
AOP底層,就是采用動態代理模式實現的。采用兩種代理:JDK的動態代理,與CGLIB的動態代理。
JDK的動態代理是面向接口的,CGLIB既可以實現有接口的,又可以實現沒有接口的。(對動態代理不了解的可以看看我的其關于動態代理的介紹)
面向切面編程,就是將交叉業務邏輯封裝成切面,利用AOP容器的功能將切面植入到主業務邏輯中。所謂交叉業務邏輯是指:通用的,與主業務邏輯無關的代碼,如安全檢查,事務日志等。
Spring的AOP的幾種用法:
通知:即我們的切面方法
異常通知
(一)前置通知?
所謂前置通知,就是這個切面方法在我們的主業務方法之前執行。
首先我們先寫一個目標接口:
//目標接口 public interface SomeServices {String doFirst();void doSecond(); } //接口實現類,也就是主業務方法類 public class SomeServiceImp implements SomeServices{@Overridepublic String doFirst() {System.out.println("print first");return null;}@Overridepublic void doSecond() {System.out.println("print second");} } //切面方法,需要實現:**MethodBeforeAdvice** 接口 public class myBeforeMethodAdvice implements MethodBeforeAdvice {//method:業務方法//args:方法參數//target:目標類 @Overridepublic void before(Method method, Object[] arg1, Object target) throws Throwable {System.out.println("執行主業務前方法");}} <!--Spring主配置文件--><bean id="service" class="com.test.beforeMethodAdvice.SomeServiceImp"/><bean id="myAdvice" class="com.test.beforeMethodAdvice.myBeforeMethodAdvice"/><bean id="ProxyService" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="service"/><!--<property name="target" value="service"/>--><property name="interceptorNames" value="myAdvice"/></bean>接著是測試方法:
public class test {@Testpublic void Test01() {String source = "com/test/beforeMethodAdvice/applicationContext.xml";ApplicationContext ac = new ClassPathXmlApplicationContext(source);SomeServices service = (SomeServices)ac.getBean("ProxyService");service.doFirst();service.doSecond();} } //控制臺輸出: //執行主業務前方法 //print first //執行主業務前方法 //print second(二)后置通知?
后置通知和前置通知雷同,只是切面方法的實現類不同,但是后置通知實現接口方法,多給用了一個returnValue參數,也就意味著我們可以獲得主業務方法的返回值,我們來看看范例:
//主業務接口 public interface SomeServices {String doFirst();void doSecond(); } //主業務方法實現類,doFirst()有返回值 package com.test.afterMethodAdvice;public class SomeServiceImp implements SomeServices{@Overridepublic String doFirst() {System.out.println("print first");return "abc";}@Overridepublic void doSecond() {System.out.println("print second");} } //實現了**AfterReturningAdvice** 接口,實現這個接口的方法有一個返回值參數 public class myAfterMethodAdvice implements AfterReturningAdvice {//returnValue:業務方法的返回值//method:業務方法屬性類//args:方法參數//target:目標類 @Overridepublic void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {System.out.println("執行業務后方法");//只能獲取到業務方法的返回值,但是不能進行修改 System.out.println(returnValue);} <!--配置文件沒什么差別--><bean id="service" class="com.test.afterMethodAdvice.SomeServiceImp"/><bean id="myAdvice" class="com.test.afterMethodAdvice.myAfterMethodAdvice"/><bean id="ProxyService" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="service"/><!--<property name="targetName" value="service"/>--><property name="interceptorNames" value="myAdvice"/></bean>測試方法:
public class test {@Testpublic void Test01() {String source = "com/test/afterMethodAdvice/applicationContext.xml";ApplicationContext ac = new ClassPathXmlApplicationContext(source);SomeServices service = (SomeServices)ac.getBean("ProxyService");service.doFirst();service.doSecond();} } //print first //執行業務后方法 //abc //print second //執行業務后方法 //null(三)環繞通知?
環繞通知就是既能實現前置通知又能實現后置通知,但是不同的是它能夠對主業務方法進行修改。
//主業務接口 public interface SomeServices {String doFirst();void doSecond(); } //主業務方法實現類 public class SomeServiceImp implements SomeServices{@Overridepublic String doFirst() {System.out.println("print first");return "abc";}@Overridepublic void doSecond() {System.out.println("print second");} } //環繞通知,切面方法類,需要實現**MethodInterceptor** //并且調用參數的proceed方法,這個方法有一個返回值,也就是主業務方法的返回值,我們可以對它進行修改。 public class MyMethodInterceptor implements MethodInterceptor {@Overridepublic Object invoke(MethodInvocation invocation) throws Throwable {System.out.println("環繞通知,業務方法前");Object result = invocation.proceed();System.out.println("環繞通知,業務方法后");if(result != null) {result = ((String)result).toUpperCase();}return result;} } //環繞通知的配置文件 <bean id="service" class="com.test.MethodInterceptor.SomeServiceImp"/><bean id="myAdvice" class="com.test.MethodInterceptor.MyMethodInterceptor"/><bean id="ProxyService" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="service"/><property name="interceptorNames" value="myAdvice"/></bean> //測試方法: public class test {@Testpublic void Test01() {String source = "com/test/MethodInterceptor/applicationContext.xml";ApplicationContext ac = new ClassPathXmlApplicationContext(source);SomeServices service = (SomeServices)ac.getBean("ProxyService");String result = service.doFirst();System.out.println(result);service.doSecond();} } //控制臺輸出: //環繞通知,業務方法前 //print first //環繞通知,業務方法后 //ABC //環繞通知,業務方法前 //print second //環繞通知,業務方法后(四)異常通知:
異常通知就是當我們的主業務方法出現異常的時候,會對這個主業務方法進行加強!
例如:我們現在的主業務方法是對用戶名和密碼進行判斷,如果用戶名或者密碼有誤,我們就就分別拋出對應的錯誤,當無誤的時候,程序正常執行。
//主業務接口,判斷用戶名,密碼是否正確 public interface SomeServices {boolean checkedUser(String username,String password) throws UserException; } //實現類,實現了對用戶和密碼的校驗 public class SomeServiceImp implements SomeServices{@Overridepublic boolean checkedUser(String username, String password)throws UserException {if(!"admin".equals(username.trim())) {throw new UsernameException("用戶名錯誤");}if(!"123".equals(password.trim())){throw new PasswordException("密碼錯誤");}return true;} }上面兩個是我們需要的主業務方法,里面我們定義了兩個異常:UsernameException,PasswordException,它們都實現了父類UserException:
//UserException public class UserException extends Exception {public UserException() {super();}public UserException(String message) {super(message);} } //UsernameException public class UsernameException extends UserException {public UsernameException() {super();}public UsernameException(String message) {super(message);} } //PasswordException public class PasswordException extends UserException {public PasswordException() {super();}public PasswordException(String message) {super(message);}}定義好上面的異常后我們就要定義我們的通知類了:
//這個異常通知需要實現ThrowsAdvice接口,接口源碼上面有,我們追蹤到源碼會發現這個接口沒有需要實現的方法,其實是由幾個供我們選擇,防止我們沒有必要的實現全部方法public class MyThrowsAdvice implements ThrowsAdvice {public void afterThrowing(Exception ex) {System.out.println("執行異常通知方法:" + ex.getMessage());} }配置文件沒有什么變化:
<bean id="service" class="com.test.afterExceptionAdvice.SomeServiceImp"/><bean id="myAdvice" class="com.test.afterExceptionAdvice.MyThrowsAdvice"/><bean id="ProxyService" class="org.springframework.aop.framework.ProxyFactoryBean"><property name="target" ref="service"/><property name="interceptorNames" value="myAdvice"/></bean>最后就是我們的測試方法:
public class test {@Testpublic void Test01() {String source = "com/test/afterExceptionAdvice/applicationContext.xml";ApplicationContext ac = new ClassPathXmlApplicationContext(source);SomeServices service = (SomeServices)ac.getBean("ProxyService");//service.checkedUser("admin", "123");//service.checkedUser("ad", "123");try {service.checkedUser("admin", "12");} catch (UserException e) {e.printStackTrace();}} } //控制臺: //**報錯** //執行異常通知方法:密碼錯誤本篇文章可能主要是代碼的實現,原理上沒有說的太多,因為前面關于動態代理的文章我也寫了一篇,所以這里就沒有贅述太多動態代理的知識。?
?
?
?
?
版權聲明:本文為博主原創文章,如需轉載請表明出處。 https://blog.csdn.net/qq_39266910/article/details/78742552?
?
轉載于:https://www.cnblogs.com/chengshun/p/9776849.html
總結
以上是生活随笔為你收集整理的08 Spring框架 AOP (一)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: mysql explain的使用
- 下一篇: JS 循环遍历 总结