Springboot特性示例

1. 依赖注入(DI)

解释:

依赖注入(DI,Dependency Injection)是 Spring 的核心概念之一。它的核心思想是将类所依赖的对象(如服务、组件)自动注入到类中,而不需要类自己创建这些依赖对象。通过 DI,Spring 可以管理类的依赖关系,从而减少了代码中的耦合性,提高了代码的灵活性和可维护性。

**”Spring 会自动将其管理为 Bean”**:Spring 是通过将 Java 类(如服务类、组件类)转换为 Bean 对象的方式来进行管理。Bean 是 Spring 容器中的对象,Spring 会自动创建这些对象并管理它们的生命周期。Spring 会通过反射和配置将这些对象注入到其他需要它们的类中。

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
 // 服务接口
public interface MessageService {
void sendMessage(String message, String receiver);
}

// 服务实现类
@Component // 将这个类标记为一个 Bean(组件),Spring 会自动将其管理为 Bean
public class EmailService implements MessageService {
@Override
public void sendMessage(String message, String receiver) {
System.out.println("Sending email to " + receiver + ": " + message);
}
}

// 消费者类(需要依赖 MessageService)
@Component // 同样标记为 Bean,Spring 会将其管理
public class UserService {
private MessageService messageService;

@Autowired // 自动注入 EmailService 实例
public UserService(MessageService messageService) {
this.messageService = messageService;
}

public void notifyUser(String message, String receiver) {
messageService.sendMessage(message, receiver); // 使用 EmailService 发送消息
}
}

// Spring 配置类
@Configuration
@ComponentScan("com.example") // 扫描指定包下的 @Component 注解,自动注册 Bean
public class AppConfig {
}

// 主程序
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

// 获取 UserService Bean
UserService userService = context.getBean(UserService.class);

// 使用 UserService 发送通知
userService.notifyUser("Hello, Spring!", "john.doe@example.com");

context.close();
}
}

解释:

  • **@Component**:标记该类是一个 Spring 管理的 Bean,Spring 会在启动时扫描类路径,并将这些类实例化为 Bean,自动将其管理。
  • **@Autowired**:表示 Spring 会自动将 EmailService 实例注入到 UserService 中,而不需要我们手动去创建 EmailService 对象。
  • **AnnotationConfigApplicationContext**:启动 Spring 容器,@ComponentScan 会扫描所有标记为 @Component 的类,并自动将它们管理为 Bean。

什么是 IOC(控制反转)?

IOC(Inversion of Control,控制反转) 是一种设计原则,它通过将控制权从程序中转移到框架或容器中来实现松耦合的架构。简单来说,IOC 让程序的控制流程不再由开发者手动编写和控制,而是通过外部容器来管理,开发者只需关注业务逻辑。

关键概念

  1. 控制反转
    • 传统的程序设计方式下,代码控制流程是由开发者手动管理的。例如,开发者负责创建对象、管理对象之间的依赖关系。
    • 在 IOC 中,这些控制(例如对象创建、对象间的依赖关系)交给框架(如 Spring)来管理。开发者不再直接控制对象的创建和销毁,而是通过容器来完成。
  2. IOC 容器
    • IOC 容器是负责管理对象生命周期和依赖注入的容器。Spring 提供的 ApplicationContext 就是一个典型的 IOC 容器。容器负责实例化、配置和管理对象的生命周期,以及处理对象之间的依赖关系。
  3. 依赖注入(DI)
    • 依赖注入(DI)是实现控制反转的一种方式,它允许将一个对象的依赖关系(例如依赖其他类的实例)通过外部方式注入到该对象中,而不需要在对象内部自行创建和管理这些依赖。
    • DI 是 IOC 的具体实现之一,通常有三种方式来实现:构造函数注入Setter 方法注入字段注入

为什么需要 IOC?

  • 解耦:传统的编程方式中,一个对象直接创建和管理其他对象,导致了强耦合,使得系统难以扩展和维护。通过 IOC,可以将对象的创建和管理交给容器,减少了类之间的依赖关系,增强了代码的可重用性和灵活性。
  • 提高可测试性:通过将控制权交给 IOC 容器,我们可以轻松地为对象提供不同的实现(如模拟对象、测试对象等),提高了代码的可测试性。
  • 增强可维护性:通过将依赖管理交给容器,开发人员可以专注于业务逻辑的编写,而不需要关心复杂的对象创建和管理工作,使得代码更加简洁,易于维护。

IOC 的工作原理

  1. 创建对象
    • 在 IOC 容器中,所有的对象都是由容器管理的。容器根据配置文件(如 XML 文件或 Java 注解)自动创建对象,而开发者不需要显式地使用 new 操作符来创建对象。
  2. 依赖注入
    • 容器还负责注入对象的依赖关系。这些依赖可以通过构造器注入、Setter 方法注入或字段注入等方式传递给对象。
  3. 生命周期管理
    • 容器不仅负责创建对象,还负责对象的生命周期管理(如销毁对象、资源释放等)。容器会在适当的时候创建对象,在不再需要时销毁对象。

IOC 示例

假设我们有一个简单的应用,其中有 UserService 需要依赖于 UserRepository

1. 传统方式(手动创建对象):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
java public class UserService {
private UserRepository userRepository;

public UserService() {
// 手动创建依赖对象
this.userRepository = new UserRepository();
}

public void saveUser(User user) {
userRepository.save(user);
}
}

public class UserRepository {
public void save(User user) {
System.out.println("Saving user: " + user.getName());
}
}

在传统方式下,UserServiceUserRepository 是强耦合的,UserService 必须手动创建 UserRepository 对象。如果要修改 UserRepository 的实现,必须修改 UserService

2. 使用 IOC(Spring):

在使用 Spring 框架的 IOC 容器时,UserServiceUserRepository 的依赖关系会由 Spring 自动管理:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
java import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.stereotype.Repository;

@Service
public class UserService {
private final UserRepository userRepository;

// 使用构造器注入(构造函数注入)
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}

public void saveUser(User user) {
userRepository.save(user);
}
}

@Repository
public class UserRepository {
public void save(User user) {
System.out.println("Saving user: " + user.getName());
}
}

3. 配置 Spring 容器

你可以通过 XML 配置或注解来配置 Spring IOC 容器。

  • XML 配置
1
2
3
4
5
6
7
8
9
xml <beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd">
<bean id="userRepository" class="com.example.UserRepository"/>
<bean id="userService" class="com.example.UserService">
<constructor-arg ref="userRepository"/>
</bean>
</beans>
  • 注解配置
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
java import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Bean;

@Configuration
@ComponentScan("com.example") // 自动扫描组件
public class AppConfig {
@Bean
public UserService userService() {
return new UserService(userRepository());
}

@Bean
public UserRepository userRepository() {
return new UserRepository();
}
}

4. 启动 Spring 容器并使用对象:

1
2
3
4
5
6
7
8
9
10
11
12
13
java import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MainApp {
public static void main(String[] args) {
AnnotationConfigApplicationContext context =
new AnnotationConfigApplicationContext(AppConfig.class);

UserService userService = context.getBean(UserService.class);
userService.saveUser(new User("John"));

context.close();
}
}

依赖注入(DI)与 IOC

  • DI(依赖注入)是 IOC(控制反转)的一种实现方式,IOC 是一种设计原则,DI 是实现 IOC 的一种具体方式。
  • DI 的核心思想是通过外部容器(如 Spring)将对象的依赖关系自动注入到类中。常见的依赖注入方式有构造器注入、Setter 注入和字段注入。

总结:

  • IOC(控制反转)是一种设计原则,它将控制逻辑从应用程序中转移到框架(如 Spring 容器),使得应用程序更加解耦,增强可维护性和可扩展性。
  • DI(依赖注入)是实现 IOC 的具体方式,Spring 通过 DI 来管理对象的创建和它们之间的依赖关系。
  • 通过使用 IOC 和 DI,Spring 容器可以自动管理对象的生命周期和依赖注入,极大地简化了开发过程,提高了代码的可维护性和可测试性。
特性 构造函数注入 Setter 方法注入 字段注入
注入方式 通过构造函数传递依赖 通过 setter 方法传递依赖 直接在字段上注入依赖
依赖关系 强依赖(必须提供依赖) 弱依赖(可选依赖) 弱依赖(可选依赖)
适用场景 必须依赖且不可变的对象 需要灵活性的对象(可选依赖) 简单和快速的依赖注入
单元测试 易于测试(依赖通过构造函数提供) 需要通过 setter 方法设置依赖 难以测试(依赖是隐式的)
代码可读性 明确且清晰 代码比较灵活,但依赖关系不明确 代码最简洁,但可读性差
推荐使用 必须的或不可变的依赖 可选的依赖 不推荐用于复杂的依赖注入

2. 面向切面编程(AOP)

解释:

面向切面编程(AOP,Aspect-Oriented Programming)是一种编程范式,它允许你将关注点(如日志记录、事务管理、安全控制等)分离到单独的模块(即切面)中。AOP 允许你在不修改源代码的情况下增强某些方法的行为。

  • 切面(Aspect):包含了增强逻辑的模块,如日志、事务。
  • 通知(Advice):增强代码的实际操作,比如在方法执行前后执行某些操作。
  • 切入点(Pointcut):定义了在哪些方法或类上应用通知(即哪些方法要进行增强)。
  • 连接点(JoinPoint):程序执行过程中的某个点,如方法调用。

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
java // 定义切面类
@Aspect // 标记为一个切面类
@Component
public class LoggingAspect {

// 切入点:匹配所有注解了 @MethodLogging 的方法
@Pointcut("@annotation(com.example.MethodLogging)")
public void methodLoggingPointcut() {}

// 通知:在方法执行前打印日志
@Before("methodLoggingPointcut()")
public void logMethodExecution(JoinPoint joinPoint) {
System.out.println("Method " + joinPoint.getSignature().getName() + " is about to be executed.");
}
}

// 定义注解
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MethodLogging {
}

// 服务类
@Component
public class MyService {

@MethodLogging // 自定义注解,触发切面增强
public void doSomething() {
System.out.println("Doing something...");
}
}

// Spring 配置类
@Configuration
@ComponentScan("com.example") // 扫描指定包下的 @Component 注解,自动注册 Bean
@EnableAspectJAutoProxy // 启用 AOP 支持
public class AppConfig {
}

// 主程序
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

// 获取 MyService Bean
MyService myService = context.getBean(MyService.class);

// 调用方法,触发切面
myService.doSomething();

context.close();
}
}

解释:

  • **@Aspect**:定义一个切面类,用来封装 AOP 逻辑。
  • **@Before**:通知类型,表示在目标方法执行之前执行。
  • **@Pointcut**:定义切入点,表示哪些方法会触发 AOP 增强。
  • **@MethodLogging**:自定义注解,用来标识需要增强的目标方法。

3. 事务管理

解释:

事务管理是指确保一系列数据库操作要么完全执行,要么完全回滚。Spring 提供了声明式事务管理,使用 @Transactional 注解,可以自动管理事务的开启、提交和回滚。

声明式事务:通过 @Transactional 注解来控制事务,Spring 会自动处理事务的提交和回滚,无需手动编写事务管理代码。

代码示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
java // 服务类
@Service
public class UserService {

private final UserRepository userRepository;

// 构造器注入
@Autowired
public UserService(UserRepository userRepository) {
this.userRepository = userRepository;
}

// 使用 @Transactional 管理事务
@Transactional // 方法执行时,如果抛出异常,Spring 会自动回滚事务
public void createUser(String username) {
userRepository.save(new User(username));
if (username.equals("error")) {
throw new RuntimeException("Simulated error");
}
}
}

// 用户仓库
@Repository
public class UserRepository {
public void save(User user) {
// 模拟保存用户到数据库
System.out.println("Saving user: " + user.getUsername());
}
}

// 用户类
public class User {
private String username;

public User(String username) {
this.username = username;
}

public String getUsername() {
return username;
}
}

// Spring 配置类
@Configuration
@EnableTransactionManagement // 启用事务管理
@ComponentScan("com.example") // 扫描 @Component 注解的 Bean
public class AppConfig {
@Bean
public DataSource dataSource() {
// 返回一个模拟数据源
return new DriverManagerDataSource("jdbc:h2:mem:testdb", "sa", "");
}

@Bean
public PlatformTransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource());
}
}

// 主程序
public class App {
public static void main(String[] args) {
AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);

UserService userService = context.getBean(UserService.class);
userService.createUser("john.doe"); // 正常事务提交
try {
userService.createUser("error"); // 模拟事务回滚
} catch (Exception e) {
System.out.println("Error occurred: " + e.getMessage());
}

context.close();
}
}

解释:

  • **@Transactional**:表示方法需要事务管理。方法执行时,如果发生异常,Spring 会回滚事务。

  • **@EnableTransactionManagement**:启用 Spring 的事务管理功能。

  1. 模块化

    在 Spring 框架中,Spring JDBCSpring ORMSpring JMSSpring Security 是四个重要的模块,它们提供了与不同技术栈的集成,使得开发人员能够更轻松地实现各种功能。下面我将分别解释每个模块的作用,并给出一些示例。

    1. Spring JDBC

    Spring JDBC 模块简化了与关系型数据库交互的操作,尤其是减少了直接使用 JDBC 时的样板代码(例如,建立连接、执行 SQL、关闭连接等)。Spring JDBC 提供了 JdbcTemplate 类,封装了 JDBC 常用操作,提供了更加简洁和一致的 API。

    核心概念:

    • JdbcTemplate:核心类,简化了数据库操作的代码,如查询、更新、插入和删除。
    • RowMapper:用于将结果集中的行映射为 对象。

    代码示例:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    java import org.springframework.jdbc.core.JdbcTemplate;
    import org.springframework.jdbc.datasource.DriverManagerDataSource;

    public class SpringJdbcExample {

    public static void main(String[] args) {
    // 配置数据源
    DriverManagerDataSource dataSource = new DriverManagerDataSource();
    dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
    dataSource.setUrl("jdbc:mysql://localhost:3306/testdb");
    dataSource.setUsername("root");
    dataSource.setPassword("password");

    // 创建 JdbcTemplate 实例
    JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);

    // 查询操作
    String sql = "SELECT COUNT(*) FROM users";
    int userCount = jdbcTemplate.queryForObject(sql, Integer.class);
    System.out.println("User count: " + userCount);

    // 更新操作
    String updateSql = "UPDATE users SET name = ? WHERE id = ?";
    jdbcTemplate.update(updateSql, "New Name", 1);
    }
    }

    特点:

    • 简化数据库操作,避免了繁琐的异常处理和连接管理。
    • 提供了易于使用的 API,使数据库操作更清晰。

    2. Spring ORM

    Spring ORM 模块集成了对象关系映射(ORM)框架,如 HibernateJPA 等,帮助开发人员简化与数据库之间的对象映射关系。它封装了常见的 ORM 操作,提供了事务管理和统一的异常处理。

    核心概念:

    • HibernateJPA:ORM 框架,用于将 Java 对象与数据库表之间进行映射。
    • JpaTemplate:与 JdbcTemplate 类似,专门用于与 JPA 交互的模板类。
    • Transaction Management:Spring ORM 集成了声明式事务管理,保证数据一致性。

    代码示例(使用 Hibernate):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    java import org.hibernate.Session;
    import org.hibernate.SessionFactory;
    import org.hibernate.cfg.Configuration;

    public class SpringOrmExample {

    public static void main(String[] args) {
    // 创建 Hibernate SessionFactory
    SessionFactory factory = new Configuration().configure("hibernate.cfg.xml")
    .addAnnotatedClass(User.class)
    .buildSessionFactory();

    // 获取 Session 对象
    Session session = factory.getCurrentSession();

    try {
    // 创建 User 对象
    User newUser = new User("John", "Doe", "john.doe@example.com");

    // 开始事务
    session.beginTransaction();

    // 保存对象
    session.save(newUser);

    // 提交事务
    session.getTransaction().commit();
    } finally {
    factory.close();
    }
    }
    }

    特点:

    • 提供了对常用 ORM 框架(如 Hibernate、JPA)的集成支持。
    • 支持声明式事务管理,简化了事务的处理。

    3. Spring JMS

    Spring JMS 模块集成了 Java Message Service(JMS)API,用于在 Java 应用程序中发送和接收消息。它简化了与 JMS 提供者(如 ActiveMQ、IBM MQ 等)的交互,并支持消息的同步和异步发送。

    核心概念:

    • MessageListener:消息监听器,用于处理接收到的消息。
    • JmsTemplate:与 JdbcTemplate 类似,封装了 JMS 消息的发送和接收。
    • QueueTopic:JMS 的两种消息类型,分别用于点对点消息传递和发布订阅模式。

    代码示例(发送消息):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    java import org.springframework.jms.core.JmsTemplate;
    import org.springframework.jms.connection.SingleConnectionFactory;
    import org.springframework.jms.core.MessageCreator;

    import javax.jms.ConnectionFactory;
    import javax.jms.Message;
    import javax.jms.Session;

    public class SpringJmsExample {

    public static void main(String[] args) {
    // 设置连接工厂(假设是一个 ActiveMQ)
    ConnectionFactory connectionFactory = new ActiveMQConnectionFactory("tcp://localhost:61616");

    // 创建 JmsTemplate
    JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);

    // 发送消息
    jmsTemplate.send("testQueue", new MessageCreator() {
    @Override
    public Message createMessage(Session session) throws JMSException {
    return session.createTextMessage("Hello JMS");
    }
    });

    System.out.println("Message sent!");
    }
    }

    特点:

    • 提供了对 JMS 的高效封装,简化了消息的发送与接收。
    • 支持同步和异步消息传递,可以集成不同的 JMS 提供者。

    4. Spring Security

    Spring Security 是一个强大的身份验证和授权框架,用于保护 Java 应用程序免受未经授权的访问。它提供了全面的安全功能,支持认证、授权、CSRF 防护、会话管理等。

    核心概念:

    • Authentication:身份验证,确保用户是其声称的身份。
    • Authorization:授权,确保用户对资源有访问权限。
    • UserDetailsService:一个接口,用于加载用户的详细信息。
    • GrantedAuthority:表示用户的角色或权限。

    代码示例(基于内存的用户认证):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    java import org.springframework.context.annotation.Configuration;
    import org.springframework.security.config.annotation.web.builders.HttpSecurity;
    import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
    import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;

    @Configuration
    @EnableWebSecurity
    public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
    // 定义哪些 URL 路径需要认证,哪些可以公开访问
    http
    .authorizeRequests()
    .antMatchers("/public/**").permitAll() // 公开路径
    .anyRequest().authenticated() // 其他路径需要认证
    .and()
    .formLogin(); // 使用表单登录
    }
    }

    特点:

    • 提供强大的认证和授权机制。
    • 内置多种身份验证方式,包括基于表单的登录、基本认证、LDAP 等。