二、AOP重点
这部分看不懂,可以先看下面的细节部分。
1、AOP简单配置
1.1、AOP使用步骤
1.1.1、导包(创建一个lib文件,用于存放jar包)
spring-aop-4.0.0.RELEASE.jar
spring-beans-4.0.0.RELEASE.jar
spring-context-4.0.0.RELEASE.jar
spring-core-4.0.0.RELEASE.jar
spring-expression-4.0.0.RELEASE.jar
commons-logging-1.1.3.jar
Spring支持面向切面编程的基础版包:
spring-aspects-4.0.0.RELEASE.jar 这是基础版的,功能不是太强大
Spring支持面向切面编程的加强版版包:(即使目标对象没有实现接口,也能创建动态代理)
com.springsource.net.sf.cglib-2.2.0.jar
com.springsource.org.aopalliance-1.0.0.jar
com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
1.1.2、写配置
(1)、创建一个conf文件,用于存放配置文件,注意这个conf文件夹,必须是源码文件夹,在src目录下创建好conf之后,需要点击菜单栏的file,选择project Structure,然后找到conf文件夹,右键选择source
然后选择apply应用,ok即可。
(2)、在conf文件夹里创建一个spring的xml文件
我们是要在配置文件里面进行配置,要让Logutils类中的方法动态切入到目标类中,就需要将目标类和切面类都加入到IOC容器中
(3)、将目标类和切面类加入到IOC容器中
(4)、在IOC容器中自动扫描包
自动扫描包需要用到context名称空间
xmlns:context="http://www.springframework.org/schema/context"
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
导入context名称空间,就必须写上这三条语句
在配置文件里写上:
<context:component-scan base-package="com.fxp"></context:component-scan>
(5)、告诉Spring到底哪个是切面类
这是一个新的注解,@Aspect,在切面类上加上这个注解,就是告诉spring这个类是切 面类
(6)、告诉Spring切面类里面的方法,在何时何地运行
告诉Spring每个方法什么时候运行,需要在方法的前面加上注解
**5个通知注解**
@Before:在目标方法运行之前运行; 前置通知
@After:在目标方法运行结束之后运行 后置通知
@AfterReturning:在目标方法正常返回之后运行 返回通知
@AfterThrowing:目标方法抛异常之后运行 异常通知
@Around:环绕 环绕通知
–
//这个方法想在执行目标方法之前运行,写切入点表达式
//切入点表达式写法:("execution(访问权限符 返回值类型 方法签名)")
//如果想在所有方法执行之前都先执行这个方法,只需要将方法签名改成:com.fxp.impl.MyCalculator.* 即可
@Before("execution(public int com.fxp.impl.MyCalculator.*(int,int ))")
public static void logStart(){
System.out.println("[xxx]开始执行.....它的参数是:xxx");
}
//这个方法想在目标方法正常执行结束之后运行
@AfterReturning("execution(public int com.fxp.impl.MyCalculator.*(int,int))")
public static void LogReturn(){
System.out.println("[xxx]正常执行完毕.....,结果是:xxx");
}
//这个方法想在目标方法出现异常的时候执行
@AfterThrowing("execution(public int com.fxp.impl.MyCalculator.*(int,int))")
public static void LogErr() {
System.out.println("[xxx]出现异常:xxx");
}
//这个方法想在方法执行结束之后运行
@After("execution(public int com.fxp.impl.MyCalculator.*(int,int))")
public static void LogEnd() {
System.out.println("方法最终执行完毕");
}
}
注意:
com.fxp.impl.MyCalculator.*(int,int )
这里一定要加上参数的类型(int,int ),否则会报错。
(7)、开启基于注解的AOP模式
需要用到aop名称空间,原理一样,具体原理在SpringIOC的context名称空间有讲解
xmlns:aop="http://www.springframework.org/schema/aop"
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd
1.1.3、测试
@Test
public void test(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("aop1.xml");
//从IOC容器中拿对象,注意:如果想要用类型获取,一定要用它的接口类型,不要用它本类
Calculator bean = ioc.getBean(Calculator.class);
bean.add(1,2);
创建IOC容器,并在IOC容器中拿到对象,注意:如果想要用类型获取,一定要用它的接口类型,不能用本类类型
运行结果:
至此,最简单的AOP功能已实现
2、源码
2.1、复制之前SpringAOP工程,并将Proxy去掉
2.2、配置文件源码
<?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: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/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<context:component-scan base-package="com.fxp"></context:component-scan>
<!--开启基于注解的AOP功能:aop名称空间-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>
需要导入aop名称空间,然后自动扫描包,开启基于注解的AOP功能
2.3、切面类源码
Logutils:
package com.fxp.util;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;
import java.lang.reflect.Method;
import java.util.Arrays;
/**
* 如何将这个类(切面类)中的这些方法(通知方法)动态的在目标方法运行的各个位置切入
* 1、导包
* spring-aop-4.0.0.RELEASE.jar
* spring-beans-4.0.0.RELEASE.jar
* spring-context-4.0.0.RELEASE.jar
* spring-core-4.0.0.RELEASE.jar
* spring-expression-4.0.0.RELEASE.jar
* commons-logging-1.1.3.jar
*
* Spring支持面向切面编程的基础版包:
* spring-aspects-4.0.0.RELEASE.jar 这是基础版的,功能不是太强大
*
* Spring支持面向切面编程的加强版版包:(即使目标对象没有实现接口,也能创建动态代理)
* com.springsource.net.sf.cglib-2.2.0.jar
* com.springsource.org.aopalliance-1.0.0.jar
* com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar
*/
//新的注解,@Aspect,这个注解就是告诉Spring这个类是切面类
@Aspect
//添加@component注解,将这个类加入到IOC容器中
@Component
public class LogUtils {
/**
* 告诉Spring每个方法什么时候运行
* 5个通知注解
* @Before:在目标方法运行之前运行; 前置通知
* @After:在目标方法运行结束之后运行 后置通知
* @AfterReturning:在目标方法正常返回之后运行 返回通知
* @AfterThrowing:目标方法抛异常之后运行 异常通知
* @Around:环绕 环绕通知
*/
//这个方法想在执行目标方法之前运行,写切入点表达式
//切入点表达式写法:("execution(访问权限符 返回值类型 方法签名(方法的参数类型))")
//如果想在所有方法执行之前都先执行这个方法,只需要将方法签名改成:com.fxp.impl.MyCalculator.*(方法的参数类型) 即可
@Before("execution(public int com.fxp.impl.MyCalculator.*(int,int ))")
public static void logStart(){
System.out.println("[xxx]开始执行.....它的参数是:xxx");
}
//这个方法想在目标方法正常执行结束之后运行
@AfterReturning("execution(public int com.fxp.impl.MyCalculator.*(int,int))")
public static void LogReturn(){
System.out.println("[xxx]正常执行完毕.....,结果是:xxx");
}
//这个方法想在目标方法出现异常的时候执行
@AfterThrowing("execution(public int com.fxp.impl.MyCalculator.*(int,int))")
public static void LogErr() {
System.out.println("[xxx]出现异常:xxx");
}
//这个方法想在方法执行结束之后运行
@After("execution(public int com.fxp.impl.MyCalculator.*(int,int))")
public static void LogEnd() {
System.out.println("方法最终执行完毕");
}
}
注意:方法的参数类型一定要写,不然会报错
2.4、测试类源码
package com.fxp.test;
import com.fxp.impl.MyCalculator;
import com.fxp.inter.Calculator;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import java.util.Arrays;
import static org.junit.Assert.*;
public class AopTest {
@Test
public void test(){
ApplicationContext ioc = new ClassPathXmlApplicationContext("aop1.xml");
//从IOC容器中拿对象,注意:如果想要用类型获取,一定要用它的接口类型,不要用它本类
Calculator bean = ioc.getBean(Calculator.class);
bean.add(1,2);
}
}
我们的目标是:在Mycalculator运行的时候,LogUtils类里面的方法能够动态切入到Mycalculator的方法里面,至此目标已基本达成。