Spring AOP的用法
阿新 • • 發佈:2017-10-20
val around 技術 pac factor 日常 三種方式 viso 可復用
AOP在事務處理、日誌、安全等方面用的很多,在日常軟件定制開發中,用好AOP可以進一步解耦,增強代碼的可復用性。平時用的最多的還是Spring AOP動態代理,其用法如下:
第一種實現的方式:通過Spring的API實現AOP。
第一步:第二步:
public interface UserService {
public void add();
public void update(int a);
public void delete();
public void search();
}
第三步:實現MethodBeforeAdvice的接口,Spring框架當中為我們提供了很多中通知。
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加用戶");
}
@Override
public void update(int a) {
System.out.println("修改用戶");
}
@Override
public void delete() {
System.out.println("刪除用戶");
}
@Override
public void search() {
System.out.println("查詢用戶");
}
第四步:配置beans.xml文件
public class Log implements MethodBeforeAdvice{
/**
* @param method 被調用方法對象
* @param args 被調用的方法的參數
* @param target 被調用的方法的目標對象
* */
@Override
public void before(Method method, Object[] args, Object target)
throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"方法被執行");
}
}
第五步:測試:
<?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.spring.service.impl.UserServiceImpl"/>
<!-- 這個切面也要配置成bean-->
<bean id="log" class="com.spring.advice.Log"/>
<aop:config>
<!--切入點,需要告訴方法在什麽去執行
expression="execution(* com.spring.service.impl.*.*(..))"
第一個* 表示所有的返回值,然後就是包名
第二個*表示所有的類對象
第三個*表示類對象所有的方法
第四個*表示所有方法下面的帶參數的方法或者是不帶參數的方法
-->
<aop:pointcut expression="execution(* com.spring.service.impl.*.*(..))" id="pointcut"/>
<!-- 在所有的方法中都切入前置通知-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
</aop:config>
</beans>
運行結果:
package com.spring.test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.spring.service.UserService;
public class Test {
public static void main(String[] args) {
ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
UserService userService = (UserService)ac.getBean("userService");
userService.update(2);
userService.add();
}
}
故前置通知可以在spring當中被執行,接下可以完善通知;
三月 12, 2017 2:22:44 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@439f5b3d: startup date [Sun Mar 12 14:22:44 GMT+08:00 2017]; root of context hierarchy
三月 12, 2017 2:22:44 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [beans.xml]
com.spring.service.impl.UserServiceImpl的update方法被執行
修改用戶
com.spring.service.impl.UserServiceImpl的add方法被執行
增加用戶
public class AfterLog implements AfterReturningAdvice{
/**
* 目標方法執行後執行的通知
* returnValue--返回值
* method 被調用的方法對象
* args 被調用的方法對象的參數
* target 被調用的方法對象的目標對象
* */
@Override
public void afterReturning(Object returnValue, Method method,
Object[] args, Object target) throws Throwable {
System.out.println(target.getClass().getName()+"的"+method.getName()+"被成功執行,返回值是:"+returnValue);
}
}
重新配置:
import java.lang.reflect.Method;
import org.springframework.aop.ThrowsAdvice;
public class ExceptionLog implements ThrowsAdvice {
public void afterThrowing(Method method,Exception ex) throws Throwable {
}
}
測試運行結果:
<!-- 這個切面也要配置成bean-->
<bean id="log" class="com.spring.advice.Log"/>
<bean id="afterLog" class="com.spring.advice.AfterLog"></bean>
<aop:config>
<!--切入點,需要告訴方法在什麽去執行
expression="execution(* com.spring.service.impl.*.*(..))"
第一個* 表示所有的返回值,然後就是包名
第二個*表示所有的類對象
第三個*表示類對象所有的方法
第四個*表示所有方法下面的帶參數的方法或者是不帶參數的方法
-->
<aop:pointcut expression="execution(* com.spring.service.impl.*.*(..))" id="pointcut"/>
<!-- 在所有的方法中都切入前置通知-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
總結:AOP的重要性,非常重要 Spring的AOP就是將公共的業務(如日誌,安全等)和業務類結合。當執行業務的時候將會把公共業務加進來。實現公共業務的重復利用。我們自己的業務就會變得更加的純粹,我們就可以關註我們的自己的業務,本質就是動態代理。 第二種方式:自定義類來實現AOP,不實現spring的自帶的通知 第一步:重新通知:
三月 12, 2017 2:28:19 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@439f5b3d: startup date [Sun Mar 12 14:28:19 GMT+08:00 2017]; root of context hierarchy
三月 12, 2017 2:28:19 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [beans.xml]
com.spring.service.impl.UserServiceImpl的update方法被執行
修改用戶
com.spring.service.impl.UserServiceImpl的update被成功執行,返回值是:null
com.spring.service.impl.UserServiceImpl的add方法被執行
增加用戶
com.spring.service.impl.UserServiceImpl的add被成功執行,返回值是:null
第二步:重新寫配置文件
public class Log {
public void before(){
System.out.println("方法執行前");
}
public void after(){
System.out.println("方法執行後");
}
}
第三種方式:通過註解實現AOP 第一步:修改log
<?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.spring.service.impl.UserServiceImpl"/>
<!-- 這個切面也要配置成bean-->
<bean id="log" class="com.spring.advice.Log"/>
<aop:config>
<!--切入點,需要告訴方法在什麽去執行
expression="execution(* com.spring.service.impl.*.*(..))"
第一個* 表示所有的返回值,然後就是包名
第二個*表示所有的類對象
第三個*表示類對象所有的方法
第四個*表示所有方法下面的帶參數的方法或者是不帶參數的方法
-->
<aop:aspect ref="log">
<aop:pointcut expression="execution(* com.spring.service.impl.*.*(..))" id="pointcut"/>
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
</beans>
第二步:修改beans.xml
package com.spring.advice;
import java.lang.reflect.Method;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.aop.MethodBeforeAdvice;
@Aspect
public class Log {
@Before("execution(* com.spring.service.impl.*.*(..))")
public void before(){
System.out.println("方法執行前");
}
@After("execution(* com.spring.service.impl.*.*(..))")
public void after(){
System.out.println("方法執行後");
}
@Around("execution(* com.spring.service.impl.*.*(..))")
public Object around(ProceedingJoinPoint jp) throws Throwable{
System.out.println("環繞前");
System.out.println("方法"+jp.getSignature());
Object result=jp.proceed();
System.out.println("環繞後");
return result;
}
}
第三步:運行:
<?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.spring.service.impl.UserServiceImpl"/>
<!-- 這個切面也要配置成bean-->
<bean id="log" class="com.spring.advice.Log"/>
<aop:aspectj-autoproxy/>
</beans>
三月 12, 2017 3:00:02 下午 org.springframework.context.support.AbstractApplicationContext prepareRefresh
信息: Refreshing org.springframework.context.support.ClassPathXmlApplicationContext@439f5b3d: startup date [Sun Mar 12 15:00:02 GMT+08:00 2017]; root of context hierarchy
三月 12, 2017 3:00:02 下午 org.springframework.beans.factory.xml.XmlBeanDefinitionReader loadBeanDefinitions
信息: Loading XML bean definitions from class path resource [beans.xml]
環繞前
方法void com.spring.service.UserService.update(int)
方法執行前
修改用戶
環繞後
方法執行後
Spring總結(五)--Spring中使用AOP三種方式
裏面最關鍵的切面配置如下:
Spring AOP的用法