SpringAOP的简单实现

纵饮孤独 提交于 2020-01-28 00:30:19

AOP,即面向切面编程,springAOP采用的是动态代理的技术

其主要作用可以做一些与业务逻辑无关,但却必须的操作,例如日志记录,权限管理,检查数据,等等。首先,来做一个小实现来方便理解

首先,建立一个maven工程,导入对于的包,我直接全部贴出来

pom.xml

<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>com.lx</groupId>
  <artifactId>springmvcdemo</artifactId>
  <version>0.0.1-SNAPSHOT</version>
  <packaging>jar</packaging>

  <name>springmvcdemo</name>
  <url>http://maven.apache.org</url>

  <properties>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
  </properties>

  <dependencies>
  <!-- spring的依赖 -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.10.RELEASE</version>
</dependency>
  
  <!-- springMVC -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>4.3.10.RELEASE</version>
</dependency>
  
  <!-- Spring AOP模块 -->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>4.3.10.RELEASE</version>
</dependency>

    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>3.8.1</version>
      <scope>test</scope>
    </dependency>
    
    

    
    
  </dependencies>
  
  
<build>

</build>
  
</project>

 

加入MathCalculator 类,这个类就是我们的业务逻辑类,我们要对它进行切面编程

MathCalculator .java

public class MathCalculator {

    public int div(int i,int j) {
        System.out.println("MathCalculator.div()被调用");
        return i/j;
    }
}

 

然后,建立一个切面类

/***
 * 切面类
 * @author hicku
 *
 *@Aspect:这个注解告诉spring,这个是一个切面类,而不是其他普通的类
 */


@Aspect
public class LogAspects {
    
    
    //抽取公共的切入点表达式
    //1,本类引用
    //2,其他的切面引用//告诉他,这个是public的,返回参数类型是int,同时目标位置为MathCalculator下面的所有方法
    @Pointcut("execution(public int com.lx.springmvcdemo.aop.MathCalculator.*(..))")
    public void printCut() {}
    
    //@before,在目标方法之前切入,切入点表达式(指在哪个方法切入)
    //@Before(value = "public int com.lx.springmvcdemo.aop.MathCalculator.*(..)")
    //也可以用
    @Before("printCut()")
    public void logStart(JoinPoint joinPoint) {
        Object[] obj=joinPoint.getArgs();
        System.out.println("除法运行"+joinPoint.getSignature().getName()+"-------参数列表:"+Arrays.asList(obj));
    }
    
    
    @After("execution(public int com.lx.springmvcdemo.aop.MathCalculator.*(..))")
    public void logEnd(JoinPoint joinPoint) {
        System.out.println("除法结束-------"+joinPoint.getSignature().getName());
    }
    
    
    //JoinPoint这个参数一定要放在其他值的前面,否则会报错
    @AfterReturning(value="printCut()",returning="result")
    public void logReturn(JoinPoint joinPoint,Object result) {
        System.out.println("除法返回正常-------运行结果("+result+")");
    }
    
    @AfterThrowing(value="printCut()",throwing="exception")
    public void logException(Exception exception) {
        System.out.println("除法异常-------异常信息:{"+exception.toString()+"}");
    }
}

如里面注释,需要@Aspect,让spring知道,这个是一个切面类

还有,注意,代码里面有两个切入代码表达式的方法。

然后,还要一个配置类,因为要用springAOP,你一定要用在spring里面注册了的bean,不然是用不了的

配置类如下:

@EnableAspectJAutoProxy
@Configuration
public class MainConfigofAOP {

    //业务逻辑类加入到容器中
    @Bean
    public MathCalculator mathCalculator() {
        return new MathCalculator();
    }
    
    //将切面类加入到容器中
    @Bean
    public LogAspects logAspects() {
        return new LogAspects();
    }
    
}

最后,写一个测试类:

public class IOCTest_AOP {

    AnnotationConfigApplicationContext applicationContext=new AnnotationConfigApplicationContext(MainConfigofAOP.class);
    
    @Test
    public void test01() {
        //使用AOP一定要使用spring容器里面注册的bean来用,不能自己new一个MathCalculator,这样做是没有用的
        //MathCalculator me=new MathCalculator();
        //me.div(1, 1);
        MathCalculator mathCalculator=    (MathCalculator) applicationContext.getBean("mathCalculator");
        mathCalculator.div(1, 0);
    }
}

 

输出结果如下:

除法运行div-------参数列表:[1, 0]
MathCalculator.div()被调用
除法结束-------div
除法异常-------异常信息:{java.lang.ArithmeticException: / by zero}

最后,总结一下:

* AOP:【动态代理】
* 指,在程序运行期间,动态的将某一段代码切入制定的位置进行运行
*
* 1,导入AOP模块:spring AOP:(spring-aspects)pom.xml的包
* 2,定义一个业务逻辑类MathCaluculator():在业务逻辑的的时候将日志打印(方法之前,运行结束,出现异常)
* 3,定义一个日志切面类(LogAspects):切面类里面的方法需要动态感知MathCaluculator运行到哪里了
* 通知方法:
* 前置通知(@Before):logStart:在目标方法div运行之前运行
* 后置通知(@After):logEnd:在目标方法div运行结束之后运行
* 返回通知(@AfterReturning):logReturn:在目标正常返回之后运行
* 异常通知(@AfterThrowing):logException:在目标出现异常之后运行
* 环绕通知(@Around):动态代理,手动推进目标方法运行(joinPoint。procced())
* 4,给切面类的目标方法标注何时何地运行(在LogAspects用通知注解)
* 5,将切面类和业务逻辑类(目标所在类)都加入到容器中
* 6,然后必须告诉spring,哪个是切面类(给切面类上加一个注解:@Aspect)
* 【7】,给配置文件中加入@EnableAspectJAutoProxy【开启基于注解的AOP模式】
* 在spring中有很多的@EnableXXXX,都是开启某一个功能的
* 其中JoinPrint这个参数一定要放到其他值的前面

* 三步:
* 1),将业务逻辑组件和切面类都加入到容器中,告诉spring哪个是切面类(@Aspect)
* 2),在切面类里面每一个通知方法上标注通知注解,告诉spring什么时候运行(切入点表达式:
* @Pointcut("execution(public int com.lx.springmvcdemo.aop.MathCalculator.*(..))"))或者是@Before什么的
* 3),上面第七步,开启注解AOP模式:@EnableAspectJAutoProxy

 

同IOC一样,这个AOP的原理也在看,

主要就是实现了这两个接口:implements SmartInstantiationAwareBeanPostProcessor, BeanFactoryAware
最后这就是后置处理器(后置处理器就是在bean初始化前后做的事情)和自动装配BeanFactory

 

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!