1.面向切面編程
在程序原有縱向執行流程中,針對某一個或某一些方法添加通知,形成橫切面的過程叫做面向切面編程
2.常用概念
原有功能:切點,pointcut
前置通知:在切點之前執行的功能,before advice
后置通知:在切點之后執行的功能,after advice
如果切點執行過程中出現異常,會觸發異常通知,throws advice
所有功能的總稱叫做切面
織入:把切面嵌入原有功能的過程叫做織入
3.Schema-based方式
每個通知都需要實現接口或類
配置spring配置文件時在<aop:config>配置
4.AspectJ方式
每個通知不需要實現接口或類
配置spring配置文件時在<aop:config>的子標簽<aop:aspect>中配置
5.Schema-based
Demo.java
public class Demo { public void demo1(){ System.out.println("demo1"); } public void demo2(){ System.out.println("demo2"); } public void demo3(){ System.out.println("demo3"); } }
(1)導入jar包
aopalliance-1.0.jar
aspectjweaver-1.9.2.jar
(2)新建前置通知類
arg0:切點方法對象Method對象
arg1:切點方法參數
arg2:切點方法所在類的對象
public class MyBeforeAdvice implements MethodBeforeAdvice{ @Override public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable { System.out.println("執行前置通知"); } }
(3)新建后置通知類
arg0:切點方法返回值
arg1:切點方法對象Method對象
arg2:切點方法參數
arg3:切點方法所在類的對象
public class MyAfterAdvice implements AfterReturningAdvice { @Override public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable { System.out.println("執行后置通知"); } }
(4)配置spring配置文件
<?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="mybefore" class="com.mxj.advice.MyBeforeAdvice"></bean> <bean id="myafter" class="com.mxj.advice.MyAfterAdvice"></bean> <!-- 配置切面 --> <aop:config> <!-- 配置切點 *通配符:匹配任意方法名,任意類名,任意一級包名;(..):任意類型參數--> <aop:pointcut expression="execution(* com.mxj.test.Demo.demo2())" id="mypoint"/> <!-- 通知 --> <aop:advisor advice-ref="mybefore" pointcut-ref="mypoint"/> <aop:advisor advice-ref="myafter" pointcut-ref="mypoint"/> </aop:config> <!-- 配置Demo類 --> <bean id="demo" class="com.mxj.test.Demo"></bean> </beans>
6.配置異常通知的步驟(AspectJ方式)
(1)只有切點報異常才能觸發異常通知
(2)在spring中只有AspectJ方式提供了異常通知的方法
(3)實現步驟
新建類,在類中寫任意名稱的方法
public class MyThrowAdvice { public void myexception(){ System.out.println("執行異常通知"); } }
在spring配置文件中配置
<aop:aspect>的ref屬性表示:方法在哪個類中
<aop:xxxx/>表示xxx通知
method:當觸發這個通知時調用哪個方法
throwing:異常對象名,必須和通知中方法參數名相同(可以不在通知中聲明異常對象)
<bean id="mythrow" class="com.mxj.advice.MyThrowAdvice"></bean> <aop:config> <aop:aspect ref="mythrow"> <aop:pointcut expression="execution(* com.mxj.test.Demo.demo1())" id="mypoint"/> <aop:after-throwing method="myexception()" pointcut-ref="mypoint" throwing="e"/> </aop:aspect> </aop:config> <bean id="demo" class="com.mxj.test.Demo"></bean>
7.異常通知(Schema-based方式)
(1)新建一個類實現throwsAdvice接口
public class MyThrow implements ThrowsAdvice{ public void afterThrowing(Exception ex) throws Throwable { System.out.println("執行異常通知:schema-base方式"); } }
(2)配置applicationContext.xml
<bean id="mythrow" class="com.mxj.advice.MyThrow"></bean> <aop:config> <aop:pointcut expression="execution(* com.mxj.test.Demo.demo1())" id="mypoint"/> <aop:advisor advice-ref="mythrow" pointcut-ref="mypoint"/> </aop:config> <bean id="demo" class="com.mxj.test.Demo"></bean>
8.環繞通知(Schema-based方式)
把前置通知和后置通知都寫到一個通知中,就組成了環繞通知
(1)新建一個類實現 MethodInterceptor(攔截器)
public class MyArround implements MethodInterceptor{ @Override public Object invoke(MethodInvocation arg0) throws Throwable { System.out.println("環繞-前置"); Object result = arg0.proceed(); System.out.println("環繞-后置"); return result; } }
(2)配置applicationContext.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="mythrow" class="com.mxj.advice.MyThrow"></bean> <aop:config> <aop:pointcut expression="execution(* com.mxj.test.Demo.demo1())" id="mypoint"/> <aop:advisor advice-ref="mythrow" pointcut-ref="mypoint"/> </aop:config> <bean id="demo" class="com.mxj.test.Demo"></bean> --> <bean id="myarround" class="com.mxj.advice.MyArround"></bean> <aop:config> <aop:pointcut expression="execution(* com.mxj.test.Demo.demo1())" id="mypoint"/> <aop:advisor advice-ref="myarround" pointcut-ref="mypoint"/> </aop:config> <bean id="demo" class="com.mxj.test.Demo"></bean> </beans>
9.AspectJ方式實現
類中方法名任意
public class MyAdvice { public void mybefore(){ System.out.println("前置"); } public void myafter(){ System.out.println("后置1"); } public void myaftering(){ System.out.println("后置2"); } public void mythrow(){ System.out.println("異常"); } public Object myarround(ProceedingJoinPoint p) throws Throwable{ System.out.println("執行環繞"); System.out.println("環繞-前置"); Object result = p.proceed(); System.out.println("環繞-后置"); return result; } }
配置spring配置文件
<aop:after/> 后置通知,是否出現異常都執行
<aop:after-returning/> 后置通知,只有當切點正確執行時執行
<aop:after/>、<aop:after-returning/>、<aop:after-throwing/>執行順序和配置順序有關
<?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="demo" class="com.mxj.test.Demo"></bean> <bean id="myadvice" class="com.mxj.advice.MyAdvice"></bean> <aop:config> <aop:aspect ref="myadvice"> <aop:pointcut expression="execution(* com.mxj.test.Demo.demo1())" id="mypoint"/> <aop:before method="mybefore" pointcut-ref="mypoint"/> <aop:after method="myafter" pointcut-ref="mypoint"/> <aop:after-returning method="myaftering" pointcut-ref="mypoint"/> <aop:after-throwing method="mythrow" pointcut-ref="mypoint"/> <aop:around method="myarround" pointcut-ref="mypoint"/> </aop:aspect> </aop:config> </beans>
10.AspectJ方式在通知中獲取切點參數
public class MyAdvice { public void mybefore(String name,int age){ System.out.println("前置"+name+" "+age); } }
配置文件
<bean id="demo" class="com.mxj.test.Demo"></bean> <bean id="myadvice" class="com.mxj.advice.MyAdvice"></bean> <aop:config> <aop:aspect ref="myadvice"> <aop:pointcut expression="execution(* com.mxj.test.Demo.demo1(String,int)) and args(name,age)" id="mypoint"/> <aop:before method="mybefore" pointcut-ref="mypoint" arg-names="name,age"/> </aop:aspect> </aop:config>
11.使用注解配置AOP(基於Aspect)
spring不會自動尋找注解,必須告訴spring哪些包下類可能有注解
(1)引入xmlns:context
(2)@Component
相當於<bean/>標簽
如果沒有參數,把類名首字母變小寫,相當於<bean id=""/>
@Component("自定義名稱")
(3)實現步驟
在spring文件中設置注解在哪些包中
<context:component-scan base-package="com.mxj.advice,com.mxj.test"></context:component-scan>
<!--
proxy-target-class true:使用cglib動態代理 false:使用jdk動態代理 --> <aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
在Demo類中添加@Componet
在方法上添加@Pointcut("")定義切點
@Component public class Demo { @Pointcut("execution(* com.mxj.test.Demo.demo1())") public void demo1() throws Exception{ System.out.println("demo1"); } }
在通知類中配置
@Component類被spring管理
@Aspect 相當於<aop:aspect/>表示通知方法在當前類中
@Component @Aspect public class MyAdvice { @Before("com.mxj.test.Demo.demo1()") public void mybefore(){ System.out.println("前置"); } @After("com.mxj.test.Demo.demo1()") public void myafter(){ System.out.println("后置"); } @AfterThrowing("com.mxj.test.Demo.demo1()") public void mythrow(){ System.out.println("異常通知"); } @Around("com.mxj.test.Demo.demo1()") public Object myarround(ProceedingJoinPoint p) throws Throwable{ System.out.println("環繞-前置"); Object result = p.proceed(); System.out.println("環繞-后置"); return result; } }
12.自動注入
在Spring配置文件中對象名和ref="id" id名相同使用自動注入,可以不配置<property/>
兩種配置方法:
(1)在<bean>中通過autowire=""配置,只對<bean>生效
(2)在<beans>中通過default-autowire=""配置,表示當前文件中所有的<bean>都走全局配置
(3)autowire=""可取值
default:默認值,根據全局default-autowire=""值,默認全局和局部都沒有配置情況下,相當於no
no:不自動注入
byName:通過名稱自動注入,在Spring容器中找類的id
byType:根據類型注入
spring容器中不可以出現兩個相同類型的<bean>
constructor:根據構造方法注入
提供對應參數的構造方法(構造方法參數中包含注入對象)
底層使用byName,構造方法參數名和其他<bean>的id相同
13.Spring中加載properties文件
(1)在src下新建xxx.properties文件
(2)在spring配置文件中先引入xmlns:context
如果需要記載多個文件逗號分割
<context:property-placeholder location="classpath:db.properties"/>
(3)添加屬性文件加載,在<beans>中開啟自動注入需要注意的地方:
SqlSessionFactoryBean的id不能叫做sqlSessionFactory
修改:把原來通過ref引用替換成value賦值,自動注入只能影響ref,不會影響value賦值
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer"> <property name="basePackage" value="com.mxj.mapper"></property> <property name="sqlSessionFactoryBeanName" value="factory"></property> </bean>
14.Spring加載屬性文件
在被Spring管理的類中通過@Value("{key}")取出properties中內容
(1)添加注解掃描
<context:component-scan base-package="com.mxj.service.impl"></context:component-scan>
(2)在類中添加
key和變量名可以不相同
變量類型任意,只要保證key對應的value能轉換成這個類型就可以
@Value("${my.demo}") private String test;
15.scope屬性
(1)<bean>的屬性
(2)作用:控制對象有效范圍(單例,多例等)
(3)<bean/>標簽對應的對象默認是單例的,無論獲取多少次都是一個對象
(4)scope可取值
singleton:默認值,單例
prototype: 多例,每次獲取重新實例化
request: 每次請求重新實例化
session:每個會話對象內,對象是單例的
application:在application對象內是單例
global session spring推出一個對象,依賴於spring-webmvc-portlet,類似於session