JAVA三大框架之Spring复习,Spring中AOP理解,面向切面编程,Spring注解使用案例。


前言

为什么要引入AOP概念呢?之前我学JAVA EE的时候也是没能搞明白这个问题,现在看来AOP还真的是个好东西。AOP (面向切面编程),就是将交叉业务逻辑封装成切面,利用 AOP 容器的功能将切面织入到主业务逻辑中。所谓交叉业务逻辑是指,通用的、与主业务逻辑无关的代码,如安全检查、事务、日志、缓存等。
若不使用 AOP,则会出现代码纠缠,即交叉业务逻辑与主业务逻辑混合在一起。这样,会使主业务逻辑变的混杂不清。
简单的来讲就是说我们日后的增加某些功能的时候不需要更改原先写好的代码。
例如,转账,在真正转账业务逻辑前后,需要权限控制、日志记录、加载事务、结束事务等交叉业务逻辑,而这些业务逻辑与主业务逻辑间并无直接关系。但,它们的代码量所占比重能达到总代码量的一半甚至还多。它们的存在,不仅产生了大量的“冗余”代码,还大大干扰了主业务逻辑—转账。


一、AOP是什么?

AOP(Aspect-OrientedProgramming,面向切面编程),可以说是OOP(Object-Oriented Programing,面向对象编程)的补充和完善。OOP引入封装、继承和多态性等概念来建立一种对象层次结构,用以模拟公共行为的一个集合。当我们需要为分散的对象引入公共行为的时候,OOP则显得无能为力。也就是说,OOP允许你定义从上到下的关系,但并不适合定义从左到右的关系。例如日志功能。日志代码往往水平地散布在所有对象层次中,而与它所散布到的对象的核心功能毫无关系。对于其他类型的代码,如安全性、异常处理和透明的持续性也是如此。这种散布在各处的无关的代码被称为横切(cross-cutting)代码,在OOP设计中,它导致了大量代码的重复,而不利于各个模块的重用。。
AOP 底层,就是采用动态代理模式实现的。采用了两种代理:JDK 的动态代理,与 CGLIB的动态代理

二、AOP的编程术语

1.切面(Aspect)

切面泛指交叉业务逻辑。上例中的事务处理、日志处理就可以理解为切面。常用的切面是通知(Advice)。实际就是对主业务逻辑的一种增强。

2.连接点(JoinPoint)

连接点指可以被切面织入的具体方法。通常业务接口中的方法均为连接点。

3. 切入点(Pointcut)

切入点指声明的一个或多个连接点的集合。通过切入点指定一组方法。
被标记为 final 的方法是不能作为连接点与切入点的。因为最终的是不能被修改的,不能被增强的。

4.目标对象(Target)

目 标 对 象 指 将 要 被 增 强 的 对 象 。 即 包 含 主 业 务 逻 辑 的 类 的 对 象 。

5.通知(Advice)

通知表示切面的执行时间,Advice 也叫增强。换个角度来说,通知定义了增强代码切入到目标代码的时间点,是目标方法执行之前执行,还是之后执行等。通知类型不同,切入时间不同。切入点定义切入的位置,通知定义切入的时间 。

三. Aspectj对AOP的实现

简介:

对于 AOP 这种编程思想,很多框架都进行了实现。Spring 就是其中之一,可以完成面向切面编程。然而,AspectJ 也实现了 AOP 的功能,且其实现方式更为简捷,使用更为方便,而且还支持注解式开发。所以,Spring 又将 AspectJ 的对于 AOP 的实现也引入到了自己的框架中。
在 Spring 中使用 AOP 开发时,一般使用 AspectJ 的实现方式。
Aspectj简介:Aspectj是一个优秀面向切面的框架,它扩展了JAVA语言,提供了强大的切面实现。
Aspectj中常用的通知有五种类型:前置通知,后置通知,环绕通知,异常通知,最终通知。
Aspectj的切入点表达式:
AspectJ 定义了专门的表达式用于指定切入点。表达式的原型是:

execution(modifiers-pattern? ret-type-pattern
declaring-type-pattern?name-pattern(param-pattern)
 throws-pattern?)

解释:

modifiers-pattern] 访问权限类型
ret-type-pattern 返回值类型
declaring-type-pattern 包名类名
name-pattern(param-pattern) 方法名(参数类型和参数个数)
throws-pattern 抛出异常类型
?表示可选的部分
以上表达式共 4 个部分。
execution(访问权限 方法返回值 方法声明(参数) 异常类型)
如下面的例子:

execution(public * (…))
指定切入点为:任意公共方法。
execution(
set*(…))
指定切入点为:任何一个以“set”开始的方法。
execution(* com.xyz.service..(…))
指定切入点为:定义在 service 包里的任意类的任意方法。
execution(* com.xyz.service….(…))
指定切入点为:定义在 service 包或者子包里的任意类的任意方法。“…”出现在类名中时,后面必须跟“*”,表示包、子包下的所有类。

Aspectj中注解的AOP实现

切面类展示:如下面的代码所示:

package com.cuit;

import javafx.scene.chart.XYChart;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.util.Date;

@Aspect
@Component
//@Autowired Bytype类型注入 应用类型注入方式时使用该方法
public class MyAspect {
    
    
    @Pointcut("execution(* com.cuit.UserService.*(..))")
    public void pointCut() {
    
    
    }

    @Before("execution(*  com.cuit.UserService.*(..)))")
    public void before() {
    
    

        System.out.println("创建成功");
        System.out.println("before 注解执行" + new Date());

    }

    /*@After("")
    public void after(){

    }*/

    @After("pointCut()")
    public void after() {
    
    

        System.out.println("after 注解执行");
    }

    @AfterThrowing(value ="execution(* * ..Service.*(..) )",     pointcut = "pointCut()", throwing = "error")
    public void afterThrowing(JoinPoint joinPoint,Throwable error) {
    
    
        System.out.println("---后置异常执行---");

    }

}

pom.xml中依赖

        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjrt</artifactId>
            <version>1.6.12</version>
        </dependency>
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.6.12</version>
        </dependency>

UserService类代码块:

package com.cuit;

import org.springframework.stereotype.Service;

@Service
public class UserService {
    
    
    /**
     * 增加用户
     */
    public void addUser(User user) {
    
    
        System.out.println("增加用户:" + user.toString());
    }

    /**
     * 删除用户
     */
    public void deleteUser(User user) {
    
    
        System.out.println("删除用户:" + user.toString());
        throw new RuntimeException("edit person throw exception");
    }

}

测试类:

    public void SpringTest() {
    
    
      
  
        ClassPathXmlApplicationContext cpxac = new ClassPathXmlApplicationContext("Spring-config.xml");
        User user1 = new User(2, "阿杜", "123456");
        user1 = (User) cpxac.getBean("user1");
        UserService userService = cpxac.getBean(UserService.class);
        userService.addUser(user1);
        System.out.println("------------------------");
        userService.deleteUser(user1);
        cpxac.close();


    }

具体代码在github上面地址为:这个也就是简单的测试了一下,大家有什么建议可以给我留言哦。https://github.com/Ernestsudo/SpringTest.git


总结

这个Spring中的AOP大致我就说到这里,俗话说“实践出真知”,欢迎大家一起交流。关于Spring的知识我后边还会继续补充,还是有很多的知识没有完善出来。

猜你喜欢

转载自blog.csdn.net/qq_41837249/article/details/113800017
今日推荐