Aop原理
SpringAop 原理就是動態代理
對於實現接口的目標類使用的是jdk動態代理
對於沒有實現任何接口的目標類,使用的是cglib的動態代理
代理類是程序在運行期間由JVM根據反射等機制動態生成的自動生成代理類和代理對象。
所謂動態就是指在程序運行前不存在代理類的字節碼文件。
SpringAop的配置方式
三種配置方式
一:SpringAop1.x 使用ProxyFactoryBean手動埃利
二:SpringAop2.x 基於命名控件的配置
三:Annotation 基於註解的配置(推薦)
Advice類型
SpringAop支持五種類型的通知(增強)
注意:多個Advice之間不允許有耦合,即多個Advice之間不允許有業務交叉。
(1):SpringAop1.x 使用ProxyFactoryBean 手動代理
配置方式:
基本用法: 添加jar包
<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>
配置Advice
定義增強類,實現相應的接口
package springaop02.advice;
import org.springframework.aop.MethodBeforeAdvice;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Date;
/**
* package_name:springaop02.advice
*
* @author:徐亞遠 Date:2020/2/19 13:18
* 項目名:springDemo01
* Description:前置通知 Advice類
* Version: 1.0
**/
public class BeforeAdvice implements MethodBeforeAdvice {
/**
* @param method
* @param args
* @param target
* @Author : 徐亞遠
* @Date : 2020/2/19 13:19
* @Description :
*/
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(method.getName()+" "+"start at:["+new Date().getTime()+"]"+" "+"args:"+Arrays.toString(args)
+"target:"+target);
}
}
配置sping.xml
<!--1:配置增強類-->
<bean id="logAdvice" class="springaop02.advice.BeforeAdvice"/>
2:配置目標類實例
<bean id="userServiceTarger" class="springaop02.service.impl.UserServlceImpl"/>
3:配置切入點
定義切入點,配置位置信息,指定那些類的哪些方法需要被執行Aop。
使用NameMathodPointcutAdvisor根據方法名匹配切入點
Advisor是Pointcut和Advice的配置器,Pointcut+Advice=Advisor
<!-- 3:配置advicor 將Advice和pointCut結合 織入的過程-->
<bean id="logAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<!-- 5:指定增強類(通知advice)-->
<property name="advice" ref="logAdvice"/>
<!-- 4: 配置切入點PoinCut 指定匹配哪些方法直接寫方法名-->
<property name="mappedNames">
<list>
<value>login</value>
</list>
</property>
</bean>
完整的spring.xml文件上面的爲解讀只需這個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"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
<!--2:配置目標類實例-->
<bean id="userServiceTarger" class="springaop02.service.impl.UserServlceImpl"/>
<!--1:配置增強類-->
<bean id="logAdvice" class="springaop02.advice.BeforeAdvice"/>
<!-- 3:配置advicor 將Advice和pointCut結合 織入的過程-->
<bean id="logAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">
<!-- 5:指定增強類(通知advice)-->
<property name="advice" ref="logAdvice"/>
<!-- 4: 配置切入點PoinCut 指定匹配哪些方法直接寫方法名-->
<property name="mappedNames">
<list>
<value>login</value>
</list>
</property>
</bean>
<!--配置代理-->
<bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--目標類實例-->
<property name="target" ref="userServiceTarger"/>
<!--目標類接口列表-->
<property name="interfaces">
<list>
<value>springaop02.service.UserService</value>
</list>
</property>
<!--交叉業務-->
<property name="interceptorNames">
<list>
<value>logAdvisor</value>
</list>
</property>
</bean>
</beans>
4:配置代理
使用ProxyFactoryBean配置代理
<!--配置代理-->
<bean id="userService" class="org.springframework.aop.framework.ProxyFactoryBean">
<!--目標類實例-->
<property name="target" ref="userServiceTarger"/>
<!--目標類接口列表-->
<property name="interfaces">
<list>
<value>springaop02.service.UserService</value>
</list>
</property>
<!--交叉業務-->
<property name="interceptorNames">
<list>
<value>logAdvisor</value>
</list>
</property>
</bean>
書寫UserService接口
package springaop02.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);
}
書寫UserService實現類UserServiceImpl類
package springaop02.service.impl;
import springaop02.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);
}
}
書寫測試類
package springaop02.controller;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import springaop02.service.UserService;
/**
* package_name:springaop02.controller
*
* @author:徐亞遠 Date:2020/2/19 13:06
* 項目名:springDemo01
* Description:TODO
* Version: 1.0
**/
public class AopOneController {
public static void main(String [] args){
ApplicationContext ac = new ClassPathXmlApplicationContext("spring.xml");
UserService userService = (UserService) ac.getBean("userService");
//使用的是jdk的動態代理 class com.sun.proxy.$Proxy4
System.out.println(userService.getClass());
userService.login("admin","xu1230" );
}
}
執行結果如圖:表明使用的是jdk動態代理技術