Spring 框架基础(04):AOP切面编程概念,几种实现方式演示

本文源码:GitHub·点这里 || GitEE·点这里

一、AOP基础简介

1、切面编程简介

AOP全称:Aspect Oriented Programming,面向切面编程。通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术。核心作用:可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的复用性和开发效率。AOP提供了取代继承和委托的一种新的方案,而且使用起来更加简洁清晰,是软件开发中的一个热点理念。

2、AOP术语

(1)、通知类型:Advice

前置通知[Before]:目标方法被调用之前;
返回通知[After-returning]:目标方法执行成功之后;
异常通知[After-throwing]:在目标方法抛出异常之后;
后置通知[After]:目标方法完成之后;
环绕通知[Around]:在目标方法执行前后环绕通知;

(2)、连接点:JoinPoint

程序执行的某一个特定位置,如类初始前后,方法的运行前后。

(3)、切点:Pointcut

连接点是指那些在指定策略下可能被拦截到的方法。

(4)、切面:Aspect

切面由切点和通知的结合。

(5)、引入:Introduction

特殊的增强,为类添加一些属性和方法。

(6)、织入:Weaving

将增强添加到目标类的具体连接点上的过程。编译期织入,这要求使用特殊编译器;类装载期织入,这要求使用特殊的类加载器;动态代理织入,在运行期为目标类添加增强生成子类的方式,Spring采用的是动态代理织入,而AspectJ采用编译期织入和类装载期织入。

(7)、代理:Proxy

类被AOP织入后生成一个结果类,它是融合了原类和增强逻辑的代理类。

二、AOP编程实现方式

案例基于如下类进行:

public class Book {
    private String bookName ;
    private String author ;
}
public interface BookService {
    void addBook (Book book) ;
}
public class BookServiceImpl implements BookService {
    @Override
    public void addBook(Book book) {
        System.out.println(book.getBookName());
        System.out.println(book.getAuthor());
    }
}

1、JDK动态代理

public class BookAopProxyFactory {
    public static BookService createService() {
        // 目标类
        final BookService bookService = new BookServiceImpl() ;
        // 切面类
        final BookAspect bookAspect = new BookAspect();
        /*
         * 代理类:将目标类(切入点)和 切面类(通知) 结合
         */
        BookService proxyBookService = (BookService) Proxy.newProxyInstance(
                BookAopProxyFactory.class.getClassLoader(),
                bookService.getClass().getInterfaces(),
                new InvocationHandler() {
                    public Object invoke(Object proxy, Method method,
                                         Object[] args) throws Throwable {
                        // 前执行
                        bookAspect.before();
                        // 执行目标类的方法
                        Object obj = method.invoke(bookService, args);
                        // 后执行
                        bookAspect.after();
                        return obj;
                    }
                });
        return proxyBookService ;
    }
}

2、CgLib字节码增强

采用字节码增强框架cglib,在运行时创建目标类的子类,从而对目标类进行增强。

public class BookAopCgLibFactory {
    public static BookService createService() {
        // 目标类
        final BookService bookService = new BookServiceImpl() ;
        // 切面类
        final BookAspect bookAspect = new BookAspect();
        // 核心代理类
        Enhancer enhancer = new Enhancer();
        // 确定父类
        enhancer.setSuperclass(bookService.getClass());
        // 设置回调函数
        enhancer.setCallback(new MethodInterceptor() {
            public Object intercept(Object proxy, Method method,
                                    Object[] args,
                                    MethodProxy methodProxy) throws Throwable {
                bookAspect.before();
                Object obj = method.invoke(bookService, args);
                bookAspect.after();
                return obj;
            }
        });
        BookServiceImpl proxyService = (BookServiceImpl) enhancer.create();
        return proxyService ;
    }
}

3、Spring半自动代理

spring 创建代理对象,从spring容器中手动的获取代理对象。

  • 配置文件
<!-- 创建目标类 -->
<bean id="bookService" class="com.spring.mvc.service.impl.BookServiceImpl" />
<!-- 创建切面类 -->
<bean id="myAspect" class="com.spring.mvc.config.BookAopSpringHalf" />
<!-- 创建代理类 -->
<bean id="proxyFactory" class="org.springframework.aop.framework.ProxyFactoryBean">
    <property name="interfaces" value="com.spring.mvc.service.BookService" />
    <property name="target" ref="bookService" />
    <property name="interceptorNames" value="myAspect" />
</bean>
  • 切面类
public class BookAopSpringHalf implements MethodInterceptor {
    @Override
    public Object invoke(MethodInvocation methodInvocation) throws Throwable {
        System.out.println("Method Before ...");
        Object obj = methodInvocation.proceed();
        System.out.println("Method After ...");
        return obj;
    }
}

4、Spring全自动代理

从spring容器获得目标类,如果配置Aop,spring将自动生成代理。

  • 配置文件
<!-- 创建目标类 -->
<bean id="bookService" class="com.spring.mvc.service.impl.BookServiceImpl" />
<!-- 创建切面类 -->
<bean id="myAspect" class="com.spring.mvc.config.BookAopSpringHalf" />
<!-- AOP编程配置 -->
<aop:config proxy-target-class="true">
    <aop:pointcut expression="execution(* com.spring.mvc.service.*.*(..))"
                  id="myPointCut"/>
    <aop:advisor advice-ref="myAspect" pointcut-ref="myPointCut"/>
</aop:config>

5、综合测试

@Test
public void test1 (){
    BookService bookService = BookAopProxyFactory.createService() ;
    Book book = new Book() ;
    book.setBookName("Spring实战");
    book.setAuthor("Craig Walls");
    bookService.addBook(book);
}
@Test
public void test2 (){
    BookService bookService = BookAopCgLibFactory.createService() ;
    Book book = new Book() ;
    book.setBookName("MySQL");
    book.setAuthor("Baron");
    bookService.addBook(book);
}
@Test
public void test3 (){
    String xmlPath = "spring-aop-half.xml";
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
    BookService bookService = (BookService) context.getBean("proxyFactory");
    Book book = new Book() ;
    book.setBookName("红楼梦");
    book.setAuthor("曹雪芹");
    bookService.addBook(book);
}
@Test
public void test4 (){
    String xmlPath = "spring-aop-all.xml";
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
    BookService bookService = (BookService) context.getBean("bookService");
    Book book = new Book() ;
    book.setBookName("西游记");
    book.setAuthor("吴承恩");
    bookService.addBook(book);
}

三、AspectJ切面编程

1、基础简介

AspectJ是一个基于Java语言的AOP框架,Spring2.0以后新增了对AspectJ切点表达式支持,通过JDK5注解技术,允许直接在类中定义切面,新版本Spring框架,推荐使用AspectJ方式来开发AOP编程。

2、XML配置方式

  • 切面类
public class BookAopAspectJ {
    public void myBefore(JoinPoint joinPoint){
        System.out.println("前置通知:" + joinPoint.getSignature().getName());
    }
    public void myAfterReturning(JoinPoint joinPoint,Object ret){
        System.out.println("后置通知:" + joinPoint.getSignature().getName() + " , -->" + ret);
    }
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("环绕通知前");
        Object obj = joinPoint.proceed();
        System.out.println("环绕通知前后");
        return obj;
    }
    public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
        System.out.println("抛出异常通知 : " + e.getMessage());
    }
    public void myAfter(JoinPoint joinPoint){
        System.out.println("最终通知");
    }
}
  • 配置文件
<!-- 创建目标类 -->
<bean id="bookService" class="com.spring.mvc.service.impl.BookServiceImpl" />
<!-- 创建切面类 -->
<bean id="myAspect" class="com.spring.mvc.config.BookAopAspectJ" />
<!-- 配置AOP编程 -->
<aop:config>
    <aop:aspect ref="myAspect">
        <aop:pointcut expression="execution(* com.spring.mvc.service.impl.BookServiceImpl.*(..))" id="myPointCut"/>
        <!-- 前置通知-->
        <aop:before method="myBefore" pointcut-ref="myPointCut"/>
        <!-- 后置通知 -->
        <aop:after-returning method="myAfterReturning" pointcut-ref="myPointCut" returning="ret" />
        <!-- 环绕通知 -->
        <aop:around method="myAround" pointcut-ref="myPointCut"/>
        <!-- 抛出异常 -->
        <aop:after-throwing method="myAfterThrowing" pointcut-ref="myPointCut" throwing="e"/>
        <!-- 最终通知 -->
        <aop:after method="myAfter" pointcut-ref="myPointCut"/>
    </aop:aspect>
</aop:config>
  • 测试方法
@Test
public void test1 (){
    String xmlPath = "spring-aop-aspectj-01.xml";
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
    BookService bookService = (BookService) context.getBean("bookService");
    Book book = new Book() ;
    book.setBookName("三国演义");
    book.setAuthor("罗贯中");
    bookService.addBook(book);
}

3、注解扫描方式

  • 配置文件
<!-- 开启类注解的扫描 -->
<context:component-scan base-package="com.spring.mvc.service.impl" />
<!-- 确定AOP注解生效 -->
<aop:aspectj-autoproxy />
<!-- 声明切面 -->
<bean id="myAspect" class="com.spring.mvc.config.AuthorAopAspectJ" />
<aop:config>
    <aop:aspect ref="myAspect" />
</aop:config>
  • 注解切面类
@Component
@Aspect
public class AuthorAopAspectJ {
    @Pointcut("execution(* com.spring.mvc.service.impl.AuthorServiceImpl.*(..))")
    private void myPointCut(){
    }
    @Before("execution(* com.spring.mvc.service.impl.AuthorServiceImpl.*(..))")
    public void myBefore(JoinPoint joinPoint){
        System.out.println("前置通知:" + joinPoint.getSignature().getName());
    }
    @AfterReturning(value="myPointCut()" ,returning="ret")
    public void myAfterReturning(JoinPoint joinPoint,Object ret){
        System.out.println("后置通知:" +
                joinPoint.getSignature().getName() + " , -->" + ret);
    }
    @Around(value = "myPointCut()")
    public Object myAround(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("环绕通知前");
        Object obj = joinPoint.proceed();
        System.out.println("环绕通知前后");
        return obj;
    }
    @AfterThrowing(
            value="execution(* com.spring.mvc.service.impl.AuthorServiceImpl.*(..))",
            throwing="e")
    public void myAfterThrowing(JoinPoint joinPoint,Throwable e){
        System.out.println("抛出异常通知 : " + e.getMessage());
    }
    @After("myPointCut()")
    public void myAfter(JoinPoint joinPoint){
        System.out.println("最终通知");
    }
}
  • 测试方法
@Test
public void test2 (){
    String xmlPath = "spring-aop-aspectj-02.xml";
    ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext(xmlPath);
    AuthorService authorService = (AuthorService) context.getBean("authorService");
    System.out.println("作者:"+authorService.getAuthor());
}

四、源代码地址

GitHub·地址
https://github.com/cicadasmile/spring-mvc-parent
GitEE·地址
https://gitee.com/cicadasmile/spring-mvc-parent

原文地址:https://blog.51cto.com/14439672/2446611

时间: 2024-10-28 03:16:58

Spring 框架基础(04):AOP切面编程概念,几种实现方式演示的相关文章

【spring框架】(三)面向切面编程(AOP)

1.AOP概念  AOP(Aspect-Oriented Programming,面向方面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善. OOP引入封装.继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合.当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力.也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系.例如日志功能.日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心

Spring 框架基础(05):事务管理机制,和实现方式

本文源码:GitHub·点这里 || GitEE·点这里 一.Spring事务管理 1.基础描述 Spring事务管理的本质就是封装了数据库对事务支持的操作,使用JDBC的事务管理机制,就是利用java.sql.Connection对象完成对事务的提交和回滚. Connection conn = DriverManager.getConnection(); try { // 自动提交设置为false conn.setAutoCommit(false); // 执行增删改查操作 // 当操作成功后

AOP基础知识及AOP切面编程之注释方法、xml配置方法

<span style="font-family: 微软雅黑; font-size: 10.5pt; letter-spacing: 0pt; ">AOP概念</span> Aspect(切面):它跟类相似,只是两者的关注点不一样,类是对物体特征的抽象,而切面是对横切性关注点的抽象 joinpoint(连接点):所谓连接点就是被拦截到的点,在spring中,这些点是方法,因为spring只支持方法类型的连接点,实际上joinpoint还可以是field或类构造器

Spring AOP 切面编程记录日志和接口执行时间

最近客户现在提出系统访问非常慢,需要优化提升访问速度,在排查了nginx.tomcat内存和服务器负载之后,判断是数据库查询速度慢,进一步排查发现是因为部分视图和表查询特别慢导致了整个系统的响应时间特别长.知道了问题之后,就需要对查询比较慢的接口进行优化,但哪些接口需要优化.哪些不需要呢?只能通过日志里的执行时间来判断,那么如何才能知道每一个接口的执行时间呢? 如果想学习Java工程化.高性能及分布式.深入浅出.微服务.Spring,MyBatis,Netty源码分析的朋友可以加我的Java高级

SpringBoot2.0 基础案例(11):配置AOP切面编程,解决日志记录业务

本文源码 GitHub地址:知了一笑 https://github.com/cicadasmile/spring-boot-base 一.AOP切面编程 1.什么是AOP编程 在软件业,AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP(面向对象编程)的延续,是软件开发中的一个热点,也是Spring框架中的一个重要内容,是函数式编程的一种衍生范型.利用AOP可以对业务逻辑的各个部

SPRING学习(十九)--基于注解的AOP切面编程

上篇中介绍了基于XML配置的AOP切面编程,除了XML配置AOP切面编程外,还可以通过注解方式实现AOP切面编程,本篇通过一个小例子来介绍基于注解的AOP编程. 1.在spring中使用AOP变成,不止要导入spring-aop.jar,还需要导入spring-aspects.jar.aspectjweaver.jar和aopalliance.jar,但是aspectjweaver.jar被spring-aspects.jar依赖,aopalliance.jar被spring-aop.jar依赖

动态代理和AOP切面编程

import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; /* * 动态代理和AOP切面编程 */ //定义一个接口 interface Person { void eat(); void breath(); } // 定义一个实现接口的实现类,即为被代理类 class Student implements Person { @Overr

spring框架学习(三)——AOP( 面向切面编程)

AOP 即 Aspect Oriented Program 面向切面编程 首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能. 所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务 所谓的周边功能,比如性能统计,日志,事务管理等等 周边功能在Spring的面向切面编程AOP思想里,即被定义为切面 在面向切面编程AOP的思想里面,核心业务功能和切面功能分别独立进行开发 然后把切面功能和核心业务功能 "编织" 在一起,这就叫AOP 原理图 1. 功能分两大类,辅助功能和

Spring Aop 切面编程

需求:之前的动态选择数据库,和现在的将某个service层的方法接入cat,都需要用到切面编程. 参考文献: http://www.blogjava.net/supercrsky/articles/174368.html http://my.oschina.net/itblog/blog/211693 一.简介 面向切面编程(AOP)提供另外一种角度来思考程序结构,通过这种方式弥补了面向对象编程(OOP)的不足. 除了类(classes)以外,AOP提供了 切面.切面对关注点进行模块化,例如横切