ToB企服应用市场:ToB评测及商务社交产业平台

标题: spring 详细讲解(ioc,依赖注入,aop) [打印本页]

作者: tsx81428    时间: 2024-9-16 15:34
标题: spring 详细讲解(ioc,依赖注入,aop)
Spring 框架既可以从 广义狭义 两个角度明白,下面讲解这两个层面的概念:
(本文重要讲解的是狭义上的spring,广义上的简朴概括)
1、spring 的含义

1. 广义上的 Spring

从广义上讲,Spring 是一个涵盖多个模块的企业级应用开发框架,它提供了从根本架构到复杂企业应用开发所需的全面办理方案。Spring 框架的模块化设计资助开发者在差别的场景中选择合适的模块或子项目。
广义的 Spring 包罗以下几个子项目:
因此,广义上的 Spring 不仅仅是一个框架,而是一个生态系统,可以用于构建从小型应用到复杂分布式系统的各种项目。
2. 狭义上的 Spring

从狭义上讲,Spring 特指 Spring Framework,它是 Spring 生态系统中的核心部分,重要提供 IoC(控制反转)容器和 AOP(面向切面编程)功能。
狭义上的 Spring 重要包括以下几个模块:
狭义的 Spring 重要指围绕核心容器(IoC)与面向切面编程(AOP)的功能,它是企业级应用开发的根本,能够资助开发者通过解耦、简化配置等方式高效开发应用程序。
总结

下面会先简朴先容一下  Spring DAO 模块 和 Spring ORM 模块(我们重要讲解的是 ioc、依赖注入、aop相干内容)
1. Spring DAO(Data Access Object)

Spring DAO 模块重要用于简化对数据库的访问,特别是简化 JDBC(Java Database Connectivity) 编程。直接利用 JDBC 进行数据库利用通常会涉及到大量样板代码,比方创建连接、执行查询、处理惩罚异常、关闭资源等。而 Spring DAO 模块通过封装这些底层利用,提供了更简洁的 API。
核心功能:

JdbcTemplate 是 Spring DAO 最常用的类,它可以执行 SQL 查询、插入、更新和删除利用,封装了底层的 JDBC API。
示例:利用 JdbcTemplate 进行数据库利用
  1. // 定义 JdbcTemplate bean
  2. @Autowired
  3. private JdbcTemplate jdbcTemplate;
  4. public void insertUser(User user) {
  5.     String sql = "INSERT INTO users (name, email) VALUES (?, ?)";
  6.     jdbcTemplate.update(sql, user.getName(), user.getEmail());
  7. }
  8. public User findUserById(Long id) {
  9.     String sql = "SELECT * FROM users WHERE id = ?";
  10.     return jdbcTemplate.queryForObject(sql, new Object[]{id}, new BeanPropertyRowMapper<>(User.class));
  11. }
复制代码
在上面的例子中,JdbcTemplate 资助我们省去了手动管理数据库连接和处理惩罚 SQL 异常的复杂工作,只需要编写简洁的 SQL 语句即可。
2. Spring ORM(Object-Relational Mapping)

Spring ORM 模块用于简化与 ORM(对象关系映射)框架的集成,比方 Hibernate、JPA(Java Persistence API)、MyBatis 等。ORM 框架用于将 Java 对象映射到数据库中的表,使得开发者可以通过操尴尬刁难象来进行数据库利用,而不是直接编写 SQL 语句。
Spring ORM 模块通过封装和简化 ORM 框架的配置和利用,使得它们能够无缝集成到 Spring 应用中。Spring ORM 不是自己实现 ORM,而是资助开发者更好地利用现有的 ORM 工具,如 Hibernate 或 JPA。
核心功能:

示例:利用 JPA 结合 Spring ORM 进行数据库利用
  1. @Entity
  2. public class User {
  3.     @Id
  4.     @GeneratedValue(strategy = GenerationType.IDENTITY)
  5.     private Long id;
  6.     private String name;
  7.     private String email;
  8. }
  9. // Spring Data JPA 提供的接口
  10. @Repository
  11. public interface UserRepository extends JpaRepository<User, Long> {
  12.     List<User> findByName(String name);
  13. }
复制代码
在这个例子中:
总结:

简朴来说,Spring DAO 更倾向于手动管理 SQL,而 Spring ORM 则是通过映射 Java 对象与数据库表来进行利用。如果你的项目是以 ORM 框架为主,可以利用 Spring ORM;如果你需要更多的 SQL 自定义控制,可以利用 Spring DAO。
2、IoC(IoC, Inversion of Control)

1. IoC 的概念

IoC 是 Spring Framework 的核心理念。它通过将对象的创建和管理职责交给容器,使对象之间的依赖关系由外部容器来处理惩罚,从而解耦组件之间的关系。
传统的编程方式下,对象 A 需要依赖对象 B 时,通常由对象 A 直接创建或获取对象 B。比方:
  1. public class A {
  2.     private B b;
  3.     public A() {
  4.         b = new B();  // A 负责创建 B 对象
  5.     }
  6. }
复制代码
这种方式的问题是,当需要改变对象 B 的实现或配置时,必须修改 A 的代码,从而增加了耦合度,降低了系统的灵活性。
将控制权从对象 A 手中交给外部的 IoC 容器,让容器负责创建和管理对象 B,并将它注入到对象 A 中。对象 A 不再关心 B 的创建过程,只需利用 B。这样,系统中的对象依赖关系就被 "反转" 了。
IoC(Inversion of Control) 是 Spring 框架的核心概念之一,它用于管理对象的生命周期和依赖关系。通过 IoC,Spring 框架接管了对象的创建和管理,使得应用程序的组件解耦,从而进步了代码的可维护性和可测试性。下面详细讲解 IoC 怎样管理 Bean 以及相干的概念。
2. IoC 容器 (spring 容器)

IoC 容器是 Spring 框架中的核心组件,它负责管理应用程序中的对象(即 Bean)。重要的 IoC 容器有两个:
3. @Bean 注解的重要功能和用途

1. 定义 Bean

2. 自定义 Bean 配置

3. Bean 的生命周期管理

4. 配置 Bean 的作用域

4. Bean 的定义与配置

1. Bean 的定义

Bean对象 是指被 Spring 容器  管理的对象。Bean 是 Spring 容器中的核心概念之一,它代表了一个受 Spring 管理的对象实例。Spring 提供了多种方式来定义 Bean:(spring 容器就是 ioc容器)
a. XML 创建bean

在 XML 配置文件中定义 Bean 是 Spring 的传统方式。这种方式在 Spring 2.x 和之前版本中广泛利用,虽然现在注解和 Java 配置更常见,但 XML 配置依然有效。
示例 XML 配置
  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3.        xsi:schemaLocation="http://www.springframework.org/schema/beans
  4. <aop:config>
  5.     <aop:pointcut id="userServiceMethods" expression="execution(* com.example.service.UserService.*(..))"/>
  6.     <aop:aspect ref="loggingAspect">
  7.         <aop:before method="logBefore" pointcut-ref="userServiceMethods"/>
  8.     </aop:aspect>
  9. </aop:config>       http://www.springframework.org/schema/beans/spring-beans.xsd">
  10.    
  11.    
  12.     <bean id="myBean" >
  13.         
  14.         <property name="name" value="example"/>
  15.     </bean>
  16. </beans>
复制代码
b. 注解创建bean

注解配置是 Spring 2.5 引入的,提供了更加简洁的方式来定义和管理 Bean。
常用注解
示例注解配置
  1. @Component
  2. public class MyBean {
  3.     @Value("example")
  4.     private String name;
  5.     // Getter 和 Setter
  6. }
复制代码
c. Java 创建bean

Java 配置是 Spring 3.0 引入的,通过 @Configuration 注解的类和 @Bean 注解的方法来定义 Bean。这种方式将配置逻辑与代码放在一起,进步了范例安全性和可重构性。
示例 Java 配置
  1. @Configuration
  2. public class AppConfig {
  3.     @Bean
  4.     public MyBean myBean() {
  5.         return new MyBean("example");
  6.     }
  7. }
复制代码
5. Bean 的获取

Bean 的获取是指从 Spring 容器中获取已定义的 Bean 实例。Spring 提供了多种方法来获取 Bean:
a. 利用 ApplicationContext

ApplicationContext 是 Spring 容器的重要接口,通过它可以获取 Bean。
示例获取 Bean
  1. // 使用 XML 配置
  2. ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
  3. MyBean myBean = context.getBean("myBean", MyBean.class);
  4. // 使用 Java 配置
  5. ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
  6. MyBean myBean = context.getBean(MyBean.class);
复制代码
b. 利用 @Autowired 注解

@Autowired 注解用于自动注入依赖的 Bean。Spring 会自动查找容器中匹配的 Bean 并注入。(下面 依赖注入 的时间会讲)
示例自动注入
  1. @Component
  2. public class MyService {
  3.     @Autowired
  4.     private MyBean myBean;
  5.     // 使用 myBean
  6. }
复制代码
6. Bean 的生命周期

Spring 容器在创建、初始化和烧毁 Bean 时,会经过以下几个生命周期阶段:
示例:初始化和烧毁方法
  1. @Component
  2. public class MyBean {
  3.    
  4.     @PostConstruct
  5.     public void init() {
  6.         // 初始化代码
  7.     }
  8.    
  9.     @PreDestroy
  10.     public void destroy() {
  11.         // 销毁代码
  12.     }
  13. }
复制代码
7. Bean 的作用域

Spring 支持多种 Bean 的作用域,决定了 Bean 的生命周期和可见性:
示例:指定 Bean 的作用域
  1. @Component
  2. @Scope("prototype")
  3. public class MyBean {
  4.     // 每次注入都创建新的实例
  5. }
复制代码
3、依赖注入

1. 依赖注入概述

依赖注入 是一种设计模式,它将对象的依赖关系从对象的内部管理转移到外部容器(如 Spring)。通过这种方式,Spring 容器负责创建和管理对象的依赖关系,从而降低组件之间的耦合,进步应用的灵活性和可测试性。
2. Bean 的定义与依赖注入

在 Spring 中,Bean 的定义和依赖注入有多种方式,可以通过 XML 配置、注解或 Java 配置来完成。
a. XML 配置中的依赖注入

XML 配置 是 Spring 的传统方式,通过 XML 文件定义 Bean 的属性和依赖关系。
示例 XML 配置
  1. <beans xmlns="http://www.springframework.org/schema/beans"
  2.        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  3.        xsi:schemaLocation="http://www.springframework.org/schema/beans
  4. <aop:config>
  5.     <aop:pointcut id="userServiceMethods" expression="execution(* com.example.service.UserService.*(..))"/>
  6.     <aop:aspect ref="loggingAspect">
  7.         <aop:before method="logBefore" pointcut-ref="userServiceMethods"/>
  8.     </aop:aspect>
  9. </aop:config>       http://www.springframework.org/schema/beans/spring-beans.xsd">
  10.    
  11.    
  12.     <bean id="myBean" >
  13.         
  14.         <property name="name" value="example"/>
  15.     </bean>
  16. </beans>         
复制代码
b. 注解配置中的依赖注入

注解配置 提供了更为简洁和灵活的方式来定义 Bean 和注入依赖。它利用注解来标识 Bean 和依赖关系。
示例注解配置
  1. @Component
  2. public class MyBean {
  3.     @Value("example")
  4.     private String name;
  5.     // Getter 和 Setter
  6. }@Componentpublic class MyService {    @Autowired    private MyBean myBean; // 自动注入    // 利用 myBean}
复制代码
c. Java 配置中的依赖注入

Java 配置 允许利用 Java 类来定义 Bean 和注入依赖。这种方式将配置和代码放在一起,提供了范例安全性。
示例 Java 配置
  1. @Configuration
  2. public class AppConfig {
  3.     @Bean
  4.     public MyBean myBean() {
  5.         return new MyBean("example");
  6.     }
  7.     @Bean
  8.     public MyService myService() {
  9.         return new MyService(myBean()); // 通过构造函数注入
  10.     }
  11. }
复制代码
3. 依赖注入的方式

依赖注入的方式的不通 重要体现在在 @Autowired注解 的位置不通
a. 构造器注入

通过构造函数将依赖注入到 Bean 中。构造器注入确保了 Bean 在创建时就有所有的依赖项。
示例
  1. @Component
  2. public class MyService {
  3.     private final MyBean myBean;
  4.     @Autowired
  5.     public MyService(MyBean myBean) {
  6.         this.myBean = myBean;
  7.     }
  8.     // 使用 myBean
  9. }
复制代码
b. 属性注入

通过 Setter 方法或字段直接注入依赖。
示例:Setter 方法注入
  1. @Component
  2. public class MyService {
  3.     private MyBean myBean;
  4.     @Autowired
  5.     public void setMyBean(MyBean myBean) {
  6.         this.myBean = myBean;
  7.     }
  8.     // 使用 myBean
  9. }
复制代码
示例:字段注入
  1. @Component
  2. public class MyService {
  3.     @Autowired
  4.     private MyBean myBean;
  5.     // 使用 myBean
  6. }
复制代码
c. 方法注入

通过普通方法注入依赖,通常用于更灵活的场景。
示例
  1. @Component
  2. public class MyService {
  3.     private MyBean myBean;
  4.     @Autowired
  5.     public void init(MyBean myBean) {
  6.         this.myBean = myBean;
  7.     }
  8.     // 使用 myBean
  9. }
复制代码
4. 依赖注入的自动装配

增补内容:
a. 按范例自动装配

Spring 根据 Bean 的范例自动匹配依赖项。
示例
  1. @Component
  2. public class MyService {
  3.     @Autowired
  4.     private MyBean myBean; // 按类型自动注入 (MyBean这个类)
  5.     // 如果 MyBean 是一个接口, 并且它有两个实现类都注册为 bean 了, 那么根据类型自动注入就会报错, 我们需要用 按照名称自动装配
  6. }
复制代码
b. 按名称自动装配

Spring 根据 Bean 的名称进行注入。
示例
  1. @Component
  2. public class MyService {
  3.     @Resource(name = "myBean")
  4.     private MyBean myBean; // 按名称注入
  5. }
复制代码
c. 利用 @Qualifier 注解

当有多个符合条件的 Bean 时,可以利用 @Qualifier 注解指定详细的 Bean。
示例
  1. @Component
  2. public class MyService {
  3.     @Autowired
  4.     @Qualifier("myBean1")
  5.     private MyBean myBean; // 指定具体的 Bean
  6. }
复制代码
4、aop

1. AOP(面向切面编程,Aspect-Oriented Programming)

AOP(Aspect-Oriented Programming,面向切面编程)是一种编程范式,旨在将 横切关注点(cross-cutting concerns)与核心业务逻辑分离。横切关注点是指那些影响多个模块的功能,比方 日志记录性能监控事务管理权限控制 等。这些功能通常与业务逻辑无关,但需要在多个地方执行。
通过 AOP,开发者可以将这些功能提取出来,以模块化的方式进行管理,而不是将这些功能分散到业务代码中,从而进步代码的可读性和可维护性。
Spring AOP 是 Spring 框架的一部分,专门用于简化横切关注点的处理惩罚。它允许开发者通过 声明式 方式(利用注解或 XML 配置)来定义切面,而不需要手动修改原有的业务代码。
2. AOP 的核心概念

在 AOP 中,有几个关键的概念需要明白:
Spring AOP 的实现方式

在 Spring 中,AOP 可以通过以下两种方式实现:(我们重要讲解的是注解方法实现)
3. AOP 通知范例详解

4. AOP 的实际应用场景

5. 基于注解方式实现 Spring AOP

在基于注解的方式中,重要利用三个注解:
1. 预备工作

在开始之前,确保 Spring AOP 的依赖已经包罗在项目中。
  1. <dependency>
  2.     <groupId>org.springframework.boot</groupId>
  3.     <artifactId>spring-boot-starter-aop</artifactId>
  4. </dependency>
复制代码
接下来,启用 Spring AOP 功能。在 Spring Boot 项目中,Spring AOP 是默认开启的。如果在非 Spring Boot 项目中,则需要手动启用:
  1. @Configuration
  2. @EnableAspectJAutoProxy
  3. public class AppConfig {
  4.     // 配置类
  5. }
复制代码
@EnableAspectJAutoProxy 注解用于开启基于 AspectJ 注解风格的 AOP 支持。
2. 定义业务类

假设我们有一个简朴的业务类 UserService,该类包罗一个方法 getUserById,用来获取用户信息。
  1. @Service
  2. public class UserService {
  3.     public String getUserById(int userId) {
  4.         System.out.println("Fetching user with ID: " + userId);
  5.         return "User" + userId;
  6.     }
  7. }
复制代码
3. 定义切面类

接下来,我们定义一个切面类 LoggingAspect 来实现日志记录功能。这个切面会在 UserService 的方法调用前后打印日志。
  1. import org.aspectj.lang.annotation.Aspect;
  2. import org.aspectj.lang.annotation.Before;
  3. import org.aspectj.lang.annotation.After;
  4. import org.aspectj.lang.annotation.Pointcut;
  5. import org.aspectj.lang.annotation.AfterReturning;
  6. import org.aspectj.lang.annotation.AfterThrowing;
  7. import org.aspectj.lang.annotation.Around;
  8. import org.aspectj.lang.ProceedingJoinPoint;
  9. import org.springframework.stereotype.Component;
  10. @Aspect
  11. @Component
  12. public class LoggingAspect {
  13.     // 定义切点,匹配 UserService 类中的所有方法
  14.     @Pointcut("execution(* com.example.service.UserService.*(..))")
  15.     public void userServiceMethods() {}
  16.     // 前置通知:在方法执行前执行
  17.     @Before("userServiceMethods()")
  18.     public void logBefore() {
  19.         System.out.println("Before method execution");
  20.     }
  21.     // 后置通知:在方法执行后执行
  22.     @After("userServiceMethods()")
  23.     public void logAfter() {
  24.         System.out.println("After method execution");
  25.     }
  26.     // 返回通知:方法成功返回结果后执行
  27.     @AfterReturning(pointcut = "userServiceMethods()", returning = "result")
  28.     public void logAfterReturning(Object result) {
  29.         System.out.println("Method returned with value: " + result);
  30.     }
  31.     // 异常通知:方法抛出异常时执行
  32.     @AfterThrowing(pointcut = "userServiceMethods()", throwing = "error")
  33.     public void logAfterThrowing(Throwable error) {
  34.         System.out.println("Method threw an exception: " + error);
  35.     }
  36.     // 环绕通知:在方法执行前后都执行,可以控制方法是否执行
  37.     @Around("userServiceMethods()")
  38.     public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
  39.         System.out.println("Before proceeding the method");
  40.         Object result = joinPoint.proceed();  // 执行目标方法
  41.         System.out.println("After proceeding the method");
  42.         return result;
  43.     }
  44. }
复制代码
6. 详细讲解各个注解

6.1 @Aspect

@Aspect 注解用于声明一个切面类。这个类中的方法会包罗横切关注点(如日志、事务等),这些方法可以在目标方法执行的差别阶段执行。
6.2 @Pointcut

@Pointcut 注解用于定义切点。切点是一个表达式,用于匹配哪些连接点(方法)会被切面拦截。Spring AOP 中常用的切点表达式有:
示例
  1. @Pointcut("execution(* com.example.service.UserService.*(..))")
  2. public void userServiceMethods() {}
复制代码
这个切点匹配 UserService 类中的所有方法。
6.3 @Before

@Before 注解定义了前置通知,它会在目标方法执行前执行。比方:
  1. @Before("userServiceMethods()")
  2. public void logBefore() {
  3.     System.out.println("Before method execution");
  4. }
复制代码
在 UserService 类的方法执行前,这段代码会先打印出 "Before method execution"。
6.4 @After

@After 注解定义了后置通知,无论目标方法是否正常返回,都会在方法执行后执行。比方:
  1. @After("userServiceMethods()")
  2. public void logAfter() {
  3.     System.out.println("After method execution");
  4. }
复制代码
这个通知会在目标方法执行完后打印 "After method execution"。
6.5 @AfterReturning

@AfterReturning 注解定义了返回通知,它会在目标方法正常返回结果后执行,可以获取到方法的返回值。
  1. @AfterReturning(pointcut = "userServiceMethods()", returning = "result")
  2. public void logAfterReturning(Object result) {
  3.     System.out.println("Method returned with value: " + result);
  4. }
复制代码
这里,result 参数用于接收目标方法的返回值,并打印它。
6.6 @AfterThrowing

@AfterThrowing 注解定义了异常通知,它会在目标方法抛出异常时执行,可以获取到异常信息。
  1. @AfterThrowing(pointcut = "userServiceMethods()", throwing = "error")
  2. public void logAfterThrowing(Throwable error) {
  3.     System.out.println("Method threw an exception: " + error);
  4. }
复制代码
当目标方法抛出异常时,这个通知会打印出异常信息。
6.7 @Around

@Around 注解定义了环绕通知,是功能最强大的一种通知范例。它不仅可以在目标方法执行前后执行,还可以决定是否执行目标方法。通常用于性能监控、事务管理等场景。
  1. @Around("userServiceMethods()")
  2. public Object logAround(ProceedingJoinPoint joinPoint) throws Throwable {
  3.     System.out.println("Before proceeding the method");
  4.     Object result = joinPoint.proceed();  // 执行目标方法
  5.     System.out.println("After proceeding the method");
  6.     return result;
  7. }
复制代码
ProceedingJoinPoint 对象可以用来执行目标方法。proceed() 方法执行目标方法,目标方法的返回值会被返回给调用者。
7. 运行结果

如果目标方法抛出异常:
环绕通知会在目标方法执行前后都执行,包裹住目标方法的执行过程。
总结

基于注解的 Spring AOP 提供了一种简洁且强大的方式来实现横切关注点的管理。通过 @Aspect、@Before、@After、@Around 等注解,开发者可以在不改变业务代码的环境下,将日志记录、事务管理、性能监控等功能模块化地注入到代码中。
9、execution 表达式匹配详解

execution 是 Spring AOP 中最常用的切点表达式之一,它用来匹配方法执行的连接点。通过 execution 表达式,可以灵活定义要拦截的目标方法。execution 表达式的语法格式如下:
  1. execution(modifiers-pattern? return-type-pattern declaring-type-pattern? method-name-pattern(param-pattern) throws-pattern?)
复制代码
execution 匹配的常见例子

  1. execution(* com.example.service.*.*(..))
复制代码
  1. execution(* com.example.service.UserService.*(..))
复制代码
  1. execution(* com.example.service.UserService.getUserById(int))
复制代码
  1. execution(String com.example.service.UserService.*(..))
复制代码
  1. execution(public * com.example.service.UserService.*(..))
复制代码
  1. execution(* com.example.service.UserService.updateUser(String, int))
复制代码
通配符的利用

比方:
  1. @Before("execution(* com.example.*.*(..))")
复制代码
总结

先写到这里... ~

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4