Spring学习手札(二)面向切面编程AOP

AOP理解java

  Aspect Oriented Program面向切面编程,经过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。spring

  可是,这种说法有些片面,由于在软件工程中,AOP的价值体现的并非代码方面,更多的是为了项目的模块化,而不单单是为了减小重复代码。express

  AOP是一种编程思想,为的是让模块自己变得更加内聚,让开发者更多的关注到业务逻辑的开发。编程

  在面向切面编程里,把功能分为核心业务功能和周边业务功能:app

    核心业务,好比登录,平常增,删数据模块化

    周边功能,统计,日志,事务管理。在Spring的面向切面编程AOP思想里,即被定义为切面测试

在面向切面的思想里,核心业务功能和切面功能单独开发,而后把两个整合在一块儿,就是AOP。spa

 

AOP实现原理代理

  AOP底层将采用代理机制进行实现日志

  接口+实现类:spring采用jdk的动态代理Proxy

  实现类:spring采用cglib字节码加强

   Spring默认使用JDK动态代理,在须要代理类而不是接口的时候,Spring会自动切换为使用cglib代理,不过如今的项目都是面向接口开发,因此JDK动态代理相对来讲用的仍是多一些。

 

Spring AOP引入了几个概念

  切面(Aspect),它是跨不一样Java类层面的横切性逻辑。能够经过XML文件中配置的普通类,也能够在类代码中使用“@Aspect” 注解去声明,在运行时,Spring会建立相似Advisor来代替它。其内部包括切入和通知。通俗的讲,是要告诉Spring何时,什么地方,作什么。

  链接点(JoinPoint),程序运行过程当中明确的点,通常是方法的调用。

  通知(Advice),AOP在特定的切入点上知性的加强处理,告诉Spring何时,作什么。通常会讲Advice模拟成一个拦截起,而且在JoinPoint上维护多个Advice,进行层拦截。好比Http鉴权的实现。

  切入点(PointCut),就是带有通知的链接点。要切入的对象,能够是类,或方法。在Spring中,全部的方法均可以认为是JoinPoint,均可以添加Advice,可是这并非全部都是咱们真正想要的,而PointCut提供了一组规则,来匹配JointPoint,给知足规则的JointPoint添加Advice。其主要用来修饰JointPoint。

 

Advice的五种通知类型

  前置通知(@Before):在目标方法被调用以前调用通知功能

  后置通知(@After):在目标方法完成以后调用通知,此时不会关心方法的输出

  返回通知(@After-Returning):在目标方法成功执行以后调用通知

  异常通知(@AfterThrowing):在目标方法抛出异常后调用通知

  环绕通知(@Around):通知包裹了被通知的方法,在被通知的方法调用以前和以后执行自定义的行为

 

作个小demo

1. 在src下新建bean包,新建Operator类

package bean;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

@Component
@Aspect
public class Operator {


//    @Pointcut("execution(* service.UserService.add()")
//    public void service() {
//    }

    @Pointcut("execution(* service.UserService.add())")
    public void  IService(){

    }

    @Before("IService()")
    public void doBefore(JoinPoint joinPoint) {
        System.out.println("  before Advice");
    }

    @After("IService()")
    public void doAfter(JoinPoint joinPoint) {
        System.out.println("  after Advice");
    }

    @AfterReturning(pointcut = "IService()", returning = "returnVal")
    public void afterReturn(JoinPoint joinPoint, Object returnVal) {
        System.out.println(" after Advice return " + returnVal);
    }

    @AfterThrowing(pointcut = "IService()", throwing = "errors")
    public void afterThrowing(JoinPoint joinPoint, Throwable errors) {
        System.out.println("afterThrowing Advice ..." + errors);
        System.out.println(" afterThrowing..");
    }

    @Around("IService()")
    public void doAround(ProceedingJoinPoint proceedingJoinPoint) {
        System.out.println(" around Advice  before");

        try {
            proceedingJoinPoint.proceed();
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        System.out.println(" around Advice  before");
    }
}

 

2. src下新建service包,新建UserService类

package service;

import org.springframework.stereotype.Service;

@Service
public class UserService {
    public void add() {
        System.out.println("UserService add.");
    }

    public boolean delete() {
        System.out.println("UserService delete ..");
        return true;
    }

    public void edit() {
        System.out.println("UserService edit ");
    }
}

3.配置XML文件,在src下新建applicationContext.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: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.xsd">

    <bean name="userService" class="service.UserService"></bean>
    <bean name="operator" class="bean.Operator"></bean>

    <aop:config>
        <aop:aspect id="operatorAspect" ref="operator">
            <aop:pointcut id="servicePointCut" expression="execution(* service.UserService.add())"></aop:pointcut>
            <aop:before pointcut-ref="servicePointCut" method="doBefore"></aop:before>
            <aop:after pointcut-ref="servicePointCut" method="doAfter"></aop:after>
            <aop:around pointcut-ref="servicePointCut" method="doAround"></aop:around>
            <aop:after-returning pointcut-ref="servicePointCut" method="afterReturn"
                                 returning="returnVal"></aop:after-returning>
            <aop:after-throwing pointcut-ref="servicePointCut" method="afterThrowing"
                                throwing="errors"></aop:after-throwing>
        </aop:aspect>
    </aop:config>
</beans>

4.测试AOP,在src下新建test.java

import bean.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.UserService;

public class test {
    @Test
    public void demo() {
        ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserService userService = (UserService) context.getBean("userService", UserService.class);
        userService.add();
    }

}

5.运行结果

相关文章
相关标签/搜索