首页 > 代码库 > spring 之 AOP

spring 之 AOP

1. AOP:aspect orentiet programming 面向切面的编程。

2. 面向切面的编程: 在不改变原有代码的情况下,增加代码新的功能。

3. 结构图:

技术分享

4. Spring 的 aop 编程有两方面的应用:

  • 声明式事务 
  • 自定义aop

5. 名词解释:

  • 切面:一个关注点的模块化。
  • 连接点:在程序执行过程中某个特定的点,在spring aop 中,一个连接点总是表示一个方法的执行。
  • 通知:在一个切面的某个特定的连接点上执行的动作。
  • 切入点:匹配连接点的断言。
  • 目标对象:被一个或者多个切面所通知的对象。
  • 织入:把切面连接到其它的应用程序类型或者对象,并创建一个被通知的对象。


6. 通知类型:

  • 前置通知(Before advice):在某连接点之前执行的通知,但这个通知不能阻止连接点之前的执行流程(除非它抛出一个异常)。
  • 后置通知(After returning advice):在某连接点正常完成后执行的通知:例如,一个方法没有抛出任何异常,正常返回。
  • 异常通知(After throwing advice):在方法抛出异常退出时执行的通知。
  • 最终通知(After (finally) advice):当某连接点退出的时候执行的通知(不论是正常返回还是异常退出)。
  • 环绕通知(Around Advice):包围一个连接点的通知,如方法调用。这是最强大的一种通知类型。环绕通知可以在方法调用前后完成自定义的行为。它也会选择是否继续执行连接点或直接返回它自己的返回值或抛出异常来结束执行。

7. 使用spring提供API来完成aop案例:

  a)  新建java项目

  b) 导入jar包

aopalliance.jar
aspectjweaver.jar
commons-logging.jar
spring-aop-4.1.6.RELEASE.jar
spring-aspects-4.1.6.RELEASE.jar
spring-beans-4.1.6.RELEASE.jar
spring-context-4.1.6.RELEASE.jar
spring-core-4.1.6.RELEASE.jar
spring-expression-4.1.6.RELEASE.jar

  c) 编写log

/**
 * 切面实现spring提供的 api。实现了前置通知。
 *
 */
public class Log implements MethodBeforeAdvice{

    @Override
    public void before(Method method, Object[] args, Object target)
            throws Throwable {
        System.out.println("info:"+new Date()+"\n "+target.getClass().getName()+"\t"+method.getName());
    }
}

  d) 编写Service

public class UserServiceImpl implements UserService{
    /**
     * 在每次实现业务方法时 需要增加一些公共的功能。
     * 如:日志,缓存,安全检查,事务等
     */
    public void save() {
        System.out.println("保存用户");
    }

    public void update() {
        System.out.println("更新用户");
    }

    public void delete() {
        System.out.println("删除用户");
    }

    public void get() {
        System.out.println("获取用户");
    }

}

  e)编写配置文件

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
        
    <bean class="cn.sxt.service.impl.UserServiceImpl"/>
    <bean id="log" class="cn.wh.log.Log"/>
    <aop:config>
        <!-- 切入点配置 
            execution 表示 匹配断言的表达式 
                第一个* 表示所有返回值 
                第二个* 表示impl包下的所有类
                第三个* 表示类中的所有方法
                (..)括号中的..表示所有参数
        -->
        <aop:pointcut expression="execution(* cn.wh.service.impl.*.*(..))" id="pointcut"/>
        <aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
    </aop:config>
</beans>

  f)测试:

public class Demo {
    public static void main(String[] args) {
        ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
        UserService userService = ac.getBean(UserService.class);
        System.out.println(userService.getClass());
        userService.save();
    }
}

8. 不通过实现api接口来实现aop,这种方式没有侵入性。

public class Log {
    public void before(){
        System.out.println("======方法执行前 执行的业务====");
    }
}

前置:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
        
    <bean class="cn.wh.service.impl.UserServiceImpl"/>
    <bean class="cn.wh.service.impl.student.StudentServiceImpl"/>
    <bean id="log" class="cn.wh.log.Log"/>
    <aop:config>
        <!-- 切入点配置 
            execution 表示 匹配断言的表达式 
                第一个* 表示所有返回值 
                第二个* 表示类中的所有方法
                (..)括号中的..表示所有参数
                impl..表示impl包下及其子包下的所有类
        -->
        <aop:pointcut expression="execution(* cn.wh.service.impl..*(..))" id="pointcut"/>
        <aop:aspect ref="log">
            <aop:before method="before" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

9.通过注解来实现aop

切面的实现:

/**
 * @Aspect表示注解一个切面
 */
@Aspect
public class Log {
    /**
     * @Before表示注解前置通知
     */
    @Before("execution(* cn.wh.service.impl..*(..))")
    public void before(){
        System.out.println("======方法执行前 执行的业务====");
    }
}

配置文件:

<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">
        
    <bean class="cn.wh.service.impl.UserServiceImpl"/>
    <bean class="cn.wh.service.impl.student.StudentServiceImpl"/>
    <bean id="log" class="cn.wh.log.Log"></bean>
    <aop:aspectj-autoproxy/>
</beans>

 

spring 之 AOP