Aop原理
SpringAop 原理就是動態代理
對於實現接口的目標類使用的是jdk動態代理
對於沒有實現任何接口的目標類,使用的是cglib的動態代理
代理類是程序在運行期間由JVM根據反射等機制動態生成的自動生成代理類和代理對象。
所謂動態就是指在程序運行前不存在代理類的字節碼文件。
SpringAop的配置方式
三種配置方式
一:SpringAop1.x 使用ProxyFactoryBean手動配置
二:SpringAop2.x 基於命名控件的配置
三:Annotation 基於註解的配置(推薦)
Advice類型
SpringAop支持五種類型的通知(增強)
注意:多個Advice之間不允許有耦合,即多個Advice之間不允許有業務交叉。
(1):SpringAop1.x 使用ProxyFactoryBean 手動代理
配置方式:
基本用法: 添加jar包
<dependencies>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.11</version>
<scope>test</scope>
</dependency>
<!--ioc01-core-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
</dependency>
<!--ioc01-bean-->
<!-- https://mvnrepository.com/artifact/org.springframework/spring-beans -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
</dependency>
<!--ioc01-context-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
</dependency>
<!--ioc01-expression-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-expression</artifactId>
</dependency>
<!--Aop依賴-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<!--cglib技術-->
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
</dependency>
</dependencies>
1:配置Advice通知
1定義增強類,實現相應的接口
package springaop04.advice;
import org.aopalliance.intercept.Joinpoint;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
import java.lang.reflect.Method;
/**
* package_name:springaop04.advice
*
* @author:徐亞遠 Date:2020/2/19 18:38
* 項目名:springDemo01
* Description:環繞通知 統計登錄執行時間
* Version: 1.0
**/
public class AroundAdvice implements MethodInterceptor {
private Long time;
public Long getTime() {
return time;
}
public void setTime(Long time) {
this.time = time;
}
/**
* Implement this method to perform extra treatments before and
* after the invocation. Polite implementations would certainly
* like to invoke {@link Joinpoint#proceed()}.
*
* @param invocation the method invocation joinpoint
* @return the result of the call to {@link Joinpoint#proceed()};
* might be intercepted by the interceptor
* @throws Throwable if the interceptors or the target object
* throws an exception
*/
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
//方法
Method method = invocation.getMethod();
//參數
Object[] args = invocation.getArguments();
//目標對象
Object target = invocation.getThis();
//執行業務方法前
System.out.println("環繞通知");
long startTime = System.currentTimeMillis();
System.out.println("方法執行前的時間:"+startTime+"ms");
//執行業務邏輯 返回值表示執行業務方法後返回的結果
Object procee = invocation.proceed();
//執行業務方法後
long endTime = System.currentTimeMillis();
System.out.println("方法執行後的時間:"+endTime+"ms");
System.out.println("方法執行花費的時間:"+(endTime-startTime)+"ms");
if (endTime-startTime > time){
System.out.println("給管理員發送信息");
}
return procee;
}
}
登錄接口的代碼
package springaop04.service;
/**
* package_name:springaop01.service
*
* author:徐亞遠 Date:2020/2/18 18:29
* 項目名:springDemo01
* Description:
**/
public interface UserService {
/**
* @Author : 徐亞遠
* @Date : 2020/2/18 20:34
* @param username
* @param password
* @Description :
*/
void login(String username, String password);
}
登錄接口的實現類
package springaop04.service.impl;
import springaop04.service.UserService;
/**
* package_name:springaop01.service.impl
* Author:徐亞遠
* Date:2020/2/18 18:29
* 項目名:springDemo01
* Desription:
**/
public class UserServlceImpl implements UserService {
/**
* @param password
* @param username
* @Author : 徐亞遠
* @Date : 2020/2/18 21:03
* @Description :
*/
@Override
public void login(String username, String password) {
System.out.println("loginUserServiceImpl登錄方法執行:" + username + " " + password);
try {
Thread.sleep(2000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
配置sping.xml
<!--配置環繞通知-->
<bean id="aroundAdvice" class="springaop04.advice.AroundAdvice">
<property name="time" value="3000"/>
</bean>
2:配置目標類實例
<!--配置目標實例-->
<bean id="userServiceTarget" class="springaop04.service.impl.UserServlceImpl"/>
3:配置Advosior**
定義切入點,配置位置信息,指定那些類的哪些方法需要被執行Aop。
使用NameMathodPointcutAdvisor根據方法名匹配切入點
Advisor是Pointcut和Advice的配置器,Pointcut+Advice=Advisor 織入的過程
<!--配置advisor-->
<bean id="aroundAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<!--配置通知-->
<property name="advice" ref="aroundAdvice"/>
<!--配置切點-->
<property name="mappedNames">
<list>
<value>login</value>
</list>
</property>
</bean>
配置代理
使用ProxyFactoryBean配置代理
<!--配置代理-->
<bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--配置目標實例-->
<property name="target" ref="userServiceTarget"/>
<!--配置目標實例參數-->
<property name="interfaces">
<list>
<value>springaop04.service.UserService</value>
</list>
</property>
<!--交叉業務-->
<property name="interceptorNames">
<list>
<value>aroundAdvisor</value>
</list>
</property>
</bean>
spring.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"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--配置目標實例-->
<bean id="userServiceTarget" class="springaop04.service.impl.UserServlceImpl"/>
<!--配置環繞通知-->
<bean id="aroundAdvice" class="springaop04.advice.AroundAdvice">
<property name="time" value="3000"/>
</bean>
<!--配置advisor-->
<bean id="aroundAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<!--配置通知-->
<property name="advice" ref="aroundAdvice"/>
<!--配置切點-->
<property name="mappedNames">
<list>
<value>login</value>
</list>
</property>
</bean>
<!--配置代理-->
<bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--配置目標實例-->
<property name="target" ref="userServiceTarget"/>
<!--配置目標實例參數-->
<property name="interfaces">
<list>
<value>springaop04.service.UserService</value>
</list>
</property>
<!--交叉業務-->
<property name="interceptorNames">
<list>
<value>aroundAdvisor</value>
</list>
</property>
</bean>
</beans>
書寫測試類
package springaop04.controller;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springaop04.service.UserService;
/**
* package_name:springaop04.controller
*
* @author:徐亞遠 Date:2020/2/19 18:54
* 項目名:springDemo01
* Description:TODO
* Version: 1.0
**/
public class AroundTest {
public static void main(String [] args){
ApplicationContext ac = new ClassPathXmlApplicationContext("aop04/spring.xml");
UserService userService = (UserService) ac.getBean("userService");
userService.login("root","root" );
System.out.println(userService.getClass());
}
}
執行結果如圖: