AOP概念以及作用
AOP开发思想
AOP相关概念
AOP开发方式
XML方式
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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--3.开启AOP命名空间-->
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl"/>
<!--2.配置共性功能成功spring控制的资源-->
<bean id="myAdvice" class="com.itheima.aop.AOPAdvice"/>
<!--4 配置AOP-->
<aop:config>
<!--5.配置切入点-->
<aop:pointcut id="pt" expression="execution(* *..*(..))"/>
<!--6.配置切面(切入点与通知的关系)-->
<aop:aspect ref="myAdvice">
<!--7.配置具体的切入点对应通知中那个操作方法-->
<aop:before method="function" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
</beans>
package com.itheima.service.impl;
import com.itheima.service.UserService;
public class UserServiceImpl implements UserService {
public void save() {
/// 0 将共性功能突出出来
//System.out.println("共性功能");
System.out.println("user servoce running ...");
}
}
package com.itheima.service;
public interface UserService {
void save();
}
package com.itheima.aop;
///1 制作通知类,在类中定义一个方法用于完全共性功能
public class AOPAdvice {
public void function() {
System.out.println("共性功能");
}
}
import com.itheima.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) classPathXmlApplicationContext.getBean("userService");
userService.save();
}
}
AOP配置(XML)
AspectJ
Aspect(切面)用于描述切入点与通知间的关系,是AOP编程中的一个概念
AspectJ是基于java语言对Aspect的实现
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--3.开启AOP命名空间-->
<bean id="userService" class="com.itheima.service.impl.UserServiceImpl"/>
<!--2.配置共性功能成功spring控制的资源-->
<bean id="myAdvice" class="com.itheima.aop.AOPAdvice"/>
<!--4 配置AOP-->
<!-- <aop:config>-->
<!-- <!–5.配置切入点–>-->
<!-- <aop:pointcut id="pt" expression="execution(* *..*(..))"/>-->
<!-- <!–6.配置切面(切入点与通知的关系)–>-->
<!-- <aop:aspect ref="myAdvice">-->
<!-- <!–7.配置具体的切入点对应通知中那个操作方法–>-->
<!-- <aop:before method="before" pointcut-ref="pt"/>-->
<!-- </aop:aspect>-->
<!-- </aop:config>-->
<!-- <!–4 配置AOP–>-->
<!-- <aop:config>-->
<!-- <!–5.配置切入点–>-->
<!-- <aop:pointcut id="pt" expression="execution(* *..*(..))"/>-->
<!-- <!–6.配置切面(切入点与通知的关系)–>-->
<!-- <aop:aspect ref="myAdvice">-->
<!-- <!–7.配置具体的切入点对应通知中那个操作方法–>-->
<!-- <aop:before method="before" pointcut-ref="pt"/>-->
<!-- </aop:aspect>-->
<!-- <!–6.配置切面(切入点与通知的关系)–>-->
<!-- <aop:aspect ref="myAdvice">-->
<!-- <!–7.配置具体的切入点对应通知中那个操作方法–>-->
<!-- <aop:before method="before" pointcut-ref="pt"/>-->
<!-- </aop:aspect>-->
<!-- </aop:config>-->
<!--4 配置AOP-->
<aop:config>
<!--5.配置切入点-->
<aop:pointcut id="pt" expression="execution(* *..*(..))"/>
<aop:pointcut id="pt2" expression="execution(* *..*(..))"/>
<!--6.配置切面(切入点与通知的关系)-->
<aop:aspect ref="myAdvice">
<!--7.配置具体的切入点对应通知中那个操作方法-->
<aop:before method="before" pointcut-ref="pt2"/>
</aop:aspect>
</aop:config>
</beans>
切入点
<!--4 配置AOP-->
<aop:config>
<!--5.配置切入点-->
<!-- <aop:pointcut id="pt" expression="execution(* *..save(..))"/>-->
<!-- 无参-->
<!-- <aop:pointcut id="pt" expression="execution(* *..save())"/>-->
<!-- 带*代表着带一个参数-->
<!-- <aop:pointcut id="pt" expression="execution(* *..save(*))"/>-->
<!-- <aop:pointcut id="pt" expression="execution(* com.itheima.service.impl.UserServiceImpl.save(..))"/>-->
<!--任意包下的-->
<!-- <aop:pointcut id="pt" expression="execution(* com.itheima..UserServiceImpl.save(..))"/>-->
<!--接口能用 前提必须要接口定义-->
<aop:pointcut id="pt" expression="execution(* com..UserService.save(..))"/>
<!--6.配置切面(切入点与通知的关系)-->
<aop:aspect ref="myAdvice">
<!--7.配置具体的切入点对应通知中那个操作方法-->
<aop:before method="before" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
</beans>
切入点的三种配置方式
<aop:config>
<!--公共切入点-->
<aop:pointcut id="pt" expression="execution(* com..UserService.save(..))"/>
<!--6.配置切面(切入点与通知的关系)-->
<aop:aspect ref="myAdvice">
<!--局部切入点-->
<aop:pointcut id="pt2" expression="execution(* com..UserService.save(..))"/>
<!--7.配置具体的切入点对应通知中那个操作方法-->
<!-- <aop:before method="before" pointcut-ref="pt2"/>-->
<!--直接配置切入点-->
<aop:before method="before" pointcut="execution(* com..UserService.save(..))"/>
</aop:aspect>
</aop:config>
五个通知类型
<aop:config>
<!--公共切入点-->
<aop:pointcut id="pt" expression="execution(* com..UserService.save(..))"/>
<!--6.配置切面(切入点与通知的关系)-->
<aop:aspect ref="myAdvice">
<!--7.配置具体的切入点对应通知中那个操作方法-->
<!-- <aop:before method="before" pointcut-ref="pt"/>-->
<!--后置通知-->
<!-- <aop:after method="after" pointcut-ref="pt"/>-->
<!-- 返回后通知,如果抛出异常以后,无法执行-->
<!-- <aop:after-returning method="afterThrowing" pointcut-ref="pt"/>-->
<!-- 抛出异常后通知-->
<!-- <aop:after-throwing method="afterThrowing" pointcut-ref="pt"/>-->
<aop:around method="around" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
package com.itheima.aop;
import org.aspectj.lang.ProceedingJoinPoint;
///1 制作通知类,在类中定义一个方法用于完全共性功能
public class AOPAdvice {
public void function() {
System.out.println("共性功能");
}
///前置通知
public void before() {
System.out.println("before");
}
/// 后置通知
public void after() {
System.out.println("after");
}
/// 返回后通知
public void afterReturing() {
System.out.println("afterReturing");
}
/// 抛出异常后通知
public void afterThrowing() {
System.out.println("afterThrowing");
}
/// 环绕通知
public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("around before");
/// 对原始方法的调用
proceedingJoinPoint.proceed();
System.out.println("around after");
}
}
通知顺序(了解)
通知获取参数数据
<aop:config>
<!--公共切入点-->
<aop:pointcut id="pt" expression="execution(* *..*(..))"/>
<!--6.配置切面(切入点与通知的关系)-->
<aop:aspect ref="myAdvice">
<!--7.配置具体的切入点对应通知中那个操作方法-->
<!-- <aop:before method="before" pointcut-ref="pt"/>-->
<aop:before method="before" pointcut="execution(* *..*(int)) && args(x)"/>
<!--后置通知-->
<aop:after method="after" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
package com.itheima.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
///1 制作通知类,在类中定义一个方法用于完全共性功能
public class AOPAdvice {
public void function() {
System.out.println("共性功能");
}
///前置通知
// public void before(JoinPoint joinPoint) {
// Object[] args = joinPoint.getArgs();
// System.out.println("before..."+args[0]);
// }
public void before(int x) {
System.out.println("before(int)..."+x);
}
/// 后置通知
public void after(JoinPoint joinPoint) {
Object[] args = joinPoint.getArgs();
System.out.println("after..."+args[0]);
}
}
通知获取返回值数据
<aop:config>
<!--公共切入点-->
<aop:pointcut id="pt" expression="execution(* *..*(..))"/>
<!--6.配置切面(切入点与通知的关系)-->
<aop:aspect ref="myAdvice">
<!--7.配置具体的切入点对应通知中那个操作方法-->
<!-- 返回后通知,如果抛出异常以后,无法执行-->
<aop:after-returning method="afterReturing" pointcut-ref="pt" returning="ret"/>
<aop:around method="around" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
/// 返回后通知
public void afterReturing(Object ret) {
System.out.println("afterReturing..." +
"" +
""+ret);
}
/// 抛出异常后通知
public void afterThrowing() {
System.out.println("afterThrowing");
}
/// 环绕通知
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("around before");
/// 对原始方法的调用
Object ret = proceedingJoinPoint.proceed();
System.out.println("around after..."+ret);
//如果是void 必须这里return null
return ret;
}
通知获取异常数据
<aop:config>
<!--公共切入点-->
<aop:pointcut id="pt" expression="execution(* *..*(..))"/>
<!--6.配置切面(切入点与通知的关系)-->
<aop:aspect ref="myAdvice">
<!-- <aop:after-throwing method="afterThrowing" pointcut-ref="pt" throwing="throwable"/>-->
<aop:around method="around" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
/// 抛出异常后通知
public void afterThrowing(Throwable throwable) {
System.out.println("afterThrowing..."+throwable.getMessage());
}
/// 环绕通知
public Object around(ProceedingJoinPoint proceedingJoinPoint) {
System.out.println("around before");
/// 对原始方法的调用
Object ret = null;
try{
ret = proceedingJoinPoint.proceed();
} catch (Throwable throwable) {
System.out.println("around...exception..."+throwable.getMessage());
}
System.out.println("around after..."+ret);
//如果是void 必须这里return null
return ret;
}
App入口
import com.itheima.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext classPathXmlApplicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) classPathXmlApplicationContext.getBean("userService");
// userService.save(666);
// int ret = userService.update();
// System.out.println("app ...."+ret);
userService.delete();
}
}
AOP配置 注解模式
@Pointcut 可以配置在变量上,但是会分配内存空间,相对于定义方法来说,定义方法,定义内存泄漏。
<?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:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd">
<!--磁盘扫描-->
<context:component-scan base-package="com.itheima"/>
<!--开启aop注解支持-->
<aop:aspectj-autoproxy/>
</beans>
import com.itheima.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class App {
public static void main(String[] args) {
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserService userService = (UserService) ctx.getBean("userService");
userService.save(666,888);
}
}
package com.itheima.service.impl;
import com.itheima.service.UserService;
import org.springframework.stereotype.Service;
@Service("userService")
public class UserServiceImpl implements UserService {
public int save(int i, int m) {
System.out.println("user service running ..."+i+","+m);
return 100;
}
}
package com.itheima.aop;
import org.aspectj.lang.annotation.Pointcut;
public class AOPPointcut {
@Pointcut("execution(* *..*(..))")
public void pt1(){}
}
package com.itheima.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
///1 制作通知类,在类中定义一个方法用于完全共性功能
@Component
@Aspect
public class AOPAdvice {
// @Pointcut("execution(* *..*(..))")
// public void pt(){}
@Before("AOPPointcut.pt1()")
public void before() {
System.out.println("before(int)...");
}
/// 后置通知
@After("AOPPointcut.pt1()")
public void after() {
System.out.println("after...");
}
/// 返回后通知
@AfterReturning("AOPPointcut.pt1()")
public void afterReturing() {
System.out.println("afterReturing");
}
/// 抛出异常后通知
@AfterThrowing("AOPPointcut.pt1()")
public void afterThrowing() {
System.out.println("afterThrowing...");
}
/// 环绕通知
@Around("AOPPointcut.pt1()")
public Object around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
System.out.println("around before");
/// 对原始方法的调用
Object ret = proceedingJoinPoint.proceed();;
System.out.println("around after...");
//如果是void 必须这里return null
return ret;
}
}
AOP注解开发通知执行顺序控制
AOP注解驱动
package com.itheima.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy
public class SpringConfig {
}
@Autowired
@Autowired
private UserService userService; 这个id是通过 @Service(“userService”)查找
package com.itheima.config;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;
@Configuration
@ComponentScan("com.itheima")
@EnableAspectJAutoProxy
public class SpringConfig {
}
package com.itheima.service;
import com.itheima.config.SpringConfig;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = SpringConfig.class)
public class UserServiceTest {
@Autowired
private UserService userService;
@Test
public void testSave() {
int ret = userService.save(888,666);
Assert.assertEquals(100,ret);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>Spring_AOP综合案例</groupId>
<artifactId>Spring_AOP综合案例</artifactId>
<version>1.0-SNAPSHOT</version>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.4</version>
</dependency>
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>5.1.47</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.16</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis</artifactId>
<version>3.5.3</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
<dependency>
<groupId>org.mybatis</groupId>
<artifactId>mybatis-spring</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-test</artifactId>
<version>5.1.9.RELEASE</version>
</dependency>
</dependencies>
</project>