spring

什么是spring

java企业级开发框架

spring有哪些优点

一、轻量级: spring大小仅仅2M左右

二、面向切面编程(Aspect-Oriented Programming, AOP)

Spring AOP允许开发者定义横切关注点(cross-cutting concerns),如日志记录、事务管理、性能监控、安全控制等,并将它们作为切面(aspect)应用到程序中。
AOP通过将横切关注点与业务逻辑分离,提高了代码的可维护性和可重用性。

--比如走到公交站、等车、上车、坐车到公司、下车、走到公司门口
在这个过程中,有一些额外的动作或关注点、AOP会帮你管理这些额外的关注点
当我走到公交站时,帮我查看公交车的实时到站时间
当我上车时,帮我刷卡支付车费

--AOP允许你定义一些切面,这些切面包含了要在程序执行过程中自动执行的额外代码(比如日志记录、性能监控、异常处理等)。你可以指定这些代码应该在哪些位置(切点)被执行(比如某个方法调用前、后或者出现异常时)。这样,你就可以把主要的业务逻辑和这些额外的功能代码分离开来,让代码更加清晰、可维护,也更容易进行单元测试

三、事务管理:(事务的概念:要么全部成功,要么全部失败)

两种方式:编程式事务和声明式事务两种事务管理方式

编程式事务
--编程式事务管理要求开发者在代码中显式地通过编程方式控制事务的边界和状态。通常涉及到使用PlatformTransactionManager接口和TransactionDefinition接口,以及TransactionStatus对象。这种方式比较繁琐,且容易出错,因此在实际开发中较少使用。

声明式事务
--声明式事务管理则是一种更为常见和推荐的方式。它允许开发者通过注解或XML配置来声明哪些方法或类需要事务支持,而无需在代码中显式地控制事务。
--Spring提供了两种声明式事务管理方式:基于注解和基于XML配置。

基于注解的事务管理
--启用注解事务管理:在Spring配置文件中添加<tx:annotation-driven>标签或使用@EnableTransactionManagement注解(在Java配置类上)。
--配置事务管理器:在Spring配置文件中配置一个PlatformTransactionManager Bean,例如DataSourceTransactionManager(对于JDBC)或JpaTransactionManager(对于JPA)。
--在需要事务的方法上添加注解:使用@Transactional注解来标记需要事务支持的方法。该注解可以定义事务的传播行为、隔离级别、超时时间等属性。

基于XML配置的事务管理
--配置事务管理器:在Spring配置文件中配置一个PlatformTransactionManager Bean。
--定义事务属性:使用<tx:advice>标签定义事务属性(如传播行为、隔离级别等),并通过<tx:attributes>标签为不同的方法定义不同的事务属性。
--将事务属性与切面关联:使用<aop:config>标签定义切面,将事务属性与需要进行事务控制的方法关联起来。这通常涉及到使用<aop:pointcut>标签定义切点,以及使用<aop:advisor>标签将切点与事务属性关联起来。

事务属性

事务属性定义了事务的边界和行为,包括:
传播行为(Propagation):定义事务如何传播到调用它的方法。例如,REQUIRED表示当前方法必须在事务中运行,如果当前没有事务则创建一个新事务;SUPPORTS表示当前方法可以在事务中运行,也可以不在事务中运行。决定事务如何传播到其他方法
隔离级别(Isolation):定义事务之间的隔离程度。例如,READ_COMMITTED表示一个事务只能读取另一个已提交事务的数据;SERIALIZABLE表示最高的隔离级别,所有的事务依次逐个执行,这样事务之间就不可能产生干扰。决定事务之间的隔离程度,即一个事务能否看到另一个事务的未提交的数据
超时时间(Timeout):定义事务的最大执行时间。
只读标志(Read-Only):设置事务为只读,表示该事务不会修改数据。这有助于数据库进行某些优化。
回滚规则(Rollback Rules):定义哪些异常会导致事务回滚。默认情况下,运行时异常和错误会导致事务回滚,而检查型异常则不会。但开发者可以通过配置来改变这一规则。

四、异常处理:(为什么处理异常?什么是异常?)

--在编写程序时,我们经常会遇到一些错误情况,比如用户输入了不合法的数据、网络请求失败、数据库查询出错等等。这些情况我们通常称之为“异常”。如果我们不处理这些异常,程序可能会突然停止运行,给用户带来不好的体验,甚至可能导致数据丢失或系统崩溃。因此,我们需要有一种机制来捕获和处理这些异常,确保程序能够优雅地应对错误情况。

--保证程序不会直接崩溃,而是能够按照我们预设的方式去处理,比如给用户返回一个友好的错误提示,或者记录错误日志以便后续排查

异常分类:在Spring MVC中,异常通常分为编译时异常和运行时异常。编译时异常可以通过try-catch进行捕获并处理,而运行时异常则通常通过Spring的异常处理机制来统一处理。
异常处理器:Spring MVC提供了多种异常处理器来统一处理异常,包括SimpleMappingExceptionResolver、自定义异常处理器(实现HandlerExceptionResolver接口)和注解方式(使用@ControllerAdvice和@ExceptionHandler)。

常用处理方式

--使用SimpleMappingExceptionResolver:这是Spring MVC提供的一个简单的异常处理器,它可以将特定的异常类型映射到特定的错误页面。比如,当程序抛出一个“找不到资源”的异常时,我们可以配置它自动跳转到一个显示“资源不存在”的页面。

<bean class="org.springframework.web.servlet.handler.SimpleMappingExceptionResolver">  
    <property name="defaultErrorView" value="/error.html"/>  
    <!-- 可以添加更多异常类型与错误页面的映射 -->  
</bean>

--自定义异常处理器:如果你需要更复杂的异常处理逻辑,可以编写一个实现了HandlerExceptionResolver接口的类,然后在这个类中定义你自己的异常处理方法。
--使用注解方式:这是Spring 3.2以后版本推荐的方式。你可以使用@ControllerAdvice和@ExceptionHandler这两个注解来定义一个全局的异常处理类。在这个类中,你可以为不同类型的异常定义不同的处理方法。当程序抛出异常时,Spring会自动调用对应的处理方法。

@ControllerAdvice用于声明一个全局异常处理类
@ExceptionHandler用于指定处理特定类型异常的方法。

@ControllerAdvice  
public class GlobalExceptionHandler {  
    @ExceptionHandler(value = Exception.class)  
    public ResponseEntity<String> handleException(Exception e) {  
        // 处理异常并返回响应  
        return new ResponseEntity<>("Error occurred: " + e.getMessage(), HttpStatus.INTERNAL_SERVER_ERROR);  
    }  
}

五、控制反转:(Inversion of Control, IoC)

Spring通过IoC容器来管理对象及其依赖关系,而不是由对象自身来控制其依赖项的实例化或查找(就是用spring容器来管理对象,我们不再创建、查找依赖对象,全部交给spring来管理)

--这个名字来源于在面向对象编程中,对象通常通过直接调用构造函数或使用工厂方法来创建和依赖其他对象。但在使用IoC容器(如Spring)的上下文中,对象的创建和依赖关系的管理不再由对象自身负责,而是由外部容器(如IoC容器)来负责。
--具体来说,IoC意味着将控制权从代码内部转移到代码外部,由外部容器来管理对象的生命周期和依赖关系。这种控制权的转移是“反转”的,因为它与传统的方式相反,传统的方式是对象主动创建和管理其依赖的对象。
--IoC容器通过读取配置文件或注解来获取关于对象的创建和依赖关系的信息,然后在运行时动态地创建对象,并将它们组装在一起。这使得对象之间的依赖关系更加灵活和可配置,同时也降低了代码之间的耦合度,提高了代码的可维护性和可测试性。
--因此,控制反转这个名字准确地描述了IoC容器如何改变传统的对象创建和依赖管理方式,将控制权从对象内部转移到外部容器。这种转变使得开发者能够更加专注于实现业务逻辑,而不需要过多地关注对象创建和依赖管理的细节。

六、依赖注入:(Dependency Injection, DI)

面向对象编程中广泛使用的设计模式、主要用于实现控制反转
核心思想是将一个对象所依赖的其他对象的创建过程从该对象本身中分离出来,从而实现解耦和增强代码的可测试性
定义:当一个对象需要与其他对象交互时,不是由这个对象自己创建或查找依赖对象,而是由外部容器(如Spring容器)将所需要的依赖对象注入到这个对象中。
目的:降低对象之间的耦合度,提高系统的可扩展性和可测试性。
实现方式:
构造函数注入(Constructor Injection)
依赖对象通过被依赖对象的构造函数传入。
主要适用于依赖对象需要在整个对象生命周期中都存在的情况,例如数据库连接对象。
可以确保依赖对象的创建和注入是在同一时间完成的,因此可以确保依赖对象的可用性。

// 课程接口  
public interface Course {  
    void study();  
}    
// 学生类  
public class Student {  
    private Course course;  
    // 通过构造函数注入课程对象  
    public Student(Course course) {  
        this.course = course;  
    }  
    public void learn() {  
        course.study();  
    }  
} 
// 应用程序中使用  
public class Main {  
    public static void main(String[] args) {  
        Course mathCourse = new MathCourse(); // 假设MathCourse实现了Course接口  
        Student student = new Student(mathCourse); // 通过构造函数注入  
        student.learn(); // 输出:学习数学课程  
    }  
}

属性注入(Property Injection,也称为Setter注入)
依赖对象通过被依赖对象的公共属性(通常是setter方法)进行注入。
这种方式灵活性较高,可以在对象创建后的任何时间点注入依赖对象。

// 课程接口和学生类与之前相同    
// 学生类增加setter方法  
public class Student {  
    private Course course;    
    // 可以有一个默认的构造函数  
    public Student() {}    
    // 通过setter方法注入课程对象  
    public void setCourse(Course course) {  
        this.course = course;  
    }    
    // ... 其他方法与之前相同  
}    
// 应用程序中使用  
public class Main {  
    public static void main(String[] args) {  
        Student student = new Student(); // 使用默认构造函数创建学生对象  
        Course mathCourse = new MathCourse(); // 假设MathCourse实现了Course接口  
        student.setCourse(mathCourse); // 通过setter方法注入  
        student.learn(); // 输出:学习数学课程  
    }  
}

接口注入
在接口中定义要注入的信息,并通过接口完成注入。
这种方式较少使用,因为它要求类实现特定的接口,可能会增加代码的复杂性。
意义:
降低耦合度:通过外部方式注入依赖关系,使得各个模块之间的依赖关系减少,有利于代码的复用和测试。
提高可扩展性:当需要添加新的功能或模块时,只需要在配置文件中添加新的依赖关系,而不需要修改原有的代码。
便于测试和调试:通过外部方式注入依赖关系,可以很容易地模拟和控制依赖对象的行为,便于进行单元测试和调试。

容器: spring创建并管理对象的生命周期和配置(通常称为bean)

对象创建和对象配置 创建bean
--常用的方法是在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="userService" class="com.example.UserService">  
        <property name="userDao" ref="userDao"/>  
    </bean>  
    <bean id="userDao" class="com.example.UserDaoImpl"/> 
</beans>

--java配置 通过@Configuration注解来标记配置类、使用@Bean注解在配置类的方法上,该方法将返回一个bean实例,方法名默认作为bean的名称 常用

@Configuration  
public class AppConfig {  
    @Bean  
    public UserService userService() {  
        UserService userService = new UserService();  
        userService.setUserDao(userDao());  
        return userService;  
    }  
    @Bean  
    public UserDao userDao() {  
        return new UserDaoImpl();  
    }  
}

--注解 在类上使用@Component、@Service、@Repository或@Controller等注解来标记组件,使其成为Spring管理的bean。通过@Autowired或@Inject注解自动注入依赖、@Scope注解用于指定bean的作用域 常用

@Service("userService")  
public class UserService {  
    private UserDao userDao;  
    @Autowired  
    public UserService(UserDao userDao) {  
        this.userDao = userDao;  
    }  
    // ...  
}  
@Repository  
public class UserDaoImpl implements UserDao {  
    // ... 
}

--Java API编程式配置 使用AnnotationConfigApplicationContext或ClassPathXmlApplicationContext等类来加载Java配置或XML配置文件,并创建Spring容器。通过registerBean等API在运行时动态注册bean 没遇见过

import org.springframework.context.annotation.AnnotationConfigApplicationContext;  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.annotation.Bean;  
import org.springframework.context.annotation.Configuration;  
@Configuration  
public class MyConfig {  
    // 通过@Bean注解静态注册一个bean  
    @Bean  
    public MyBean myBean() {  
        return new MyBean();  
    }  
    public static void main(String[] args) {  
        // 创建AnnotationConfigApplicationContext实例  
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext();  
        // 注册配置类  
        context.register(MyConfig.class);  
        // 动态注册一个bean(虽然这不是直接通过registerBean方法,但效果类似)  
        context.getBeanFactory().registerSingleton("dynamicBean", new DynamicBean());  
        // 刷新容器,触发bean的创建和初始化  
        context.refresh();  
        // 获取并使用bean  
        MyBean myBean = context.getBean(MyBean.class);  
        DynamicBean dynamicBean = context.getBean("dynamicBean", DynamicBean.class);  
        // ... 使用bean做一些操作  
        // 关闭容器  
        context.close();  
    }  
    static class MyBean {  
        // ...  
    }  
    static class DynamicBean {  
        // ...  
    }  
}
/**在示例中,MyConfig类是一个配置类,它使用@Configuration注解,并通过@Bean注解静态注册了
一个MyBean类型的bean。然后,在main方法中,我们创建了一个AnnotationConfigApplicationContext实例,
并注册了MyConfig配置类。接着,我们通过context.getBeanFactory().registerSingleton()方法动态注册
了一个名为"dynamicBean"的DynamicBean类型的bean。注意,这里使用的是BeanFactory的registerSingleton方法
,它用于注册一个单例bean。最后,我们通过context.refresh()方法刷新容器,这会触发所有bean的创建和初始化。
然后我们可以像通常那样从容器中获取并使用bean。*/

--使用@ComponentScan自动扫描 在配置类上使用@ComponentScan注解,Spring会自动扫描指定包下的组件并注册为bean 常用

@Configuration  
@ComponentScan(basePackages = "com.example")  
public class AppConfig {  
    // ...  
}

对象管理 生命周期
--初始化 Spring支持使用JSR-250的@PostConstruct注解来标记一个方法,该方法会在依赖注入完成后立即被自动调用。这通常用于执行一些初始化逻辑。

@Component  
public class MyBean {  
    @PostConstruct  
    public void init() {  
        // 初始化逻辑  
    }  
}

--init-method属性(XML配置) 在XML配置文件中,你可以为bean指定一个init-method,Spring会在创建bean后立即调用该方法。

<bean id="myBean" class="com.example.MyBean" init-method="init"/>

--InitializingBean接口 实现InitializingBean接口的bean会在所有属性设置完成后调用afterPropertiesSet()方法。

@Component  
public class MyBean implements InitializingBean {  
    @Override  
    public void afterPropertiesSet() throws Exception {  
        // 初始化逻辑  
    }  
}

销毁
--@PreDestroy注解 Spring同样支持JSR-250的@PreDestroy注解来标记一个方法,该方法会在bean销毁之前被自动调用。这通常用于执行一些清理逻辑。

@Component  
public class MyBean {  
    @PreDestroy  
    public void destroy() {  
        // 清理逻辑  
    }  
}

--destroy-method属性(XML配置) 在XML配置文件中,你可以为bean指定一个destroy-method,Spring会在销毁bean之前调用该方法。

<bean id="myBean" class="com.example.MyBean" destroy-method="destroy"/>

--DisposableBean接口 实现DisposableBean接口的bean会在销毁前调用destroy()方法。

@Component  
public class MyBean implements DisposableBean {  
    @Override  
    public void destroy() throws Exception {  
        // 清理逻辑  
    }  
}

Spring容器中的销毁方法
1)销毁方法的定义:
销毁方法并不是Bean本身的方法,而是在Spring容器关闭时,由容器调用的一个特定方法。
销毁方法可以通过多种方式定义,包括但不限于实现DisposableBean接口、在@Bean注解中指定destroyMethod、在XML配置中指定destroy-method等
2)实现DisposableBean接口
通过实现org.springframework.beans.factory.DisposableBean接口,并在Bean中实现destroy()方法,可以在Spring容器关闭时执行清理操作

@Component  
public class MyBean implements DisposableBean {  
    @Override  
    public void destroy() throws Exception {  
        // 清理资源的代码  
        System.out.println("MyBean is being destroyed.");  
    }  
}

3)使用@Bean注解的destroyMethod属性

@Configuration  
public class AppConfig {  
    @Bean(destroyMethod = "close")  
    public MyResource myResource() {  
        return new MyResource();  
    }  
}  
public class MyResource {  
    public void close() {  
        // 清理资源的代码  
    }  
}

4)在XML配置中指定destroy-method

<bean id="myResource" class="com.example.MyResource" destroy-method="close" />

5)执行时机
销毁方法仅对单例(Singleton)Bean有效。对于原型(Prototype)Bean,Spring容器不负责其销毁,因此销毁方法不会被调用。
如果Bean实现了org.springframework.context.SmartLifecycle接口,则可以通过stop()方法进行清理,而不是通过销毁方法。
销毁方法的执行顺序可以通过@DependsOn注解或XML配置中的depends-on属性进行控制。
6)注意事项
销毁方法会在Spring容器关闭时执行,这通常发生在应用程序关闭或上下文被销毁时。
--生命周期回调 Spring还提供了BeanPostProcessor接口,允许你在bean的初始化前后添加额外的逻辑。这可以通过实现postProcessBeforeInitialization和postProcessAfterInitialization方法来实现。

七、MVC框架:

MVC(Model-View-Controller)是一种软件设计模式,它将应用程序的逻辑分离成三个独立的组件

--模型(Model):负责处理数据的读取、存储和操作,以及业务规则的处理。模型是应用程序的数据和业务逻辑的表示,它通常独立于用户界面,可以在不同的视图和控制器之间共享和重用。
--视图(View):负责展示数据给用户,并接收用户的输入。视图通常是根据模型的数据进行渲染和更新的,它可以是Web页面、图形界面或命令行界面等。
--控制器(Controller):负责接收用户的输入并根据输入调用相应的模型逻辑。控制器将用户的请求转发给模型进行处理,并将处理结果传递给视图进行展示。同时,控制器还可以处理视图的事件和状态变化。

Spring MVC框架的特点

--轻量级:Spring MVC是一个轻量级的框架,不需要繁琐的配置就可以快速搭建Web应用。
--灵活性:Spring MVC框架采用了面向接口的设计,可以根据需要实现自定义的处理器、视图解析器等组件。
--高效性:Spring MVC框架使用了基于注解的控制器、拦截器等技术,可以提高处理请求的效率。
--易扩展性:Spring MVC框架支持插件式的架构设计,可以方便地扩展功能。
--与Spring框架集成:Spring MVC框架与Spring框架无缝集成,可以利用Spring的依赖注入、AOP等功能。
--组件化:Spring MVC框架将Web应用拆分成多个组件,如控制器、视图解析器、拦截器等,使得代码更加清晰和易维护。

八、数据访问/集成模块

Spring框架提供了强大的数据访问和集成功能,允许开发者以声明式或编程式的方式与各种数据访问技术(如关系型数据库、NoSQL数据库、消息队列、JMS、JPA、MyBatis等)进行交互
--Spring JDBC:
Spring JDBC模块提供了对JDBC(Java Database Connectivity)的简化封装,允许开发者使用模板方法(如JdbcTemplate)来执行SQL语句,而无需手动管理资源(如连接、语句、结果集)。

jdbcTemplate.query()方法执行SQL查询,并使用UserRowMapper将查询结果映射为User对象列表
定义一个Java对象 User

public class User {  
    private int id;  
    private String name;  
    private String email;  
    // getters and setters ...  
    @Override  
    public String toString() {  
        return "User [id=" + id + ", name=" + name + ", email=" + email + "]";  
    }  
}

实现RowMapper接口来将结果集映射为Java对象。

public class UserRowMapper implements RowMapper<User> {  
    @Override  
    public User mapRow(ResultSet rs, int rowNum) throws SQLException {  
        User user = new User();  
        user.setId(rs.getInt("id"));  
        user.setName(rs.getString("name"));  
        user.setEmail(rs.getString("email"));  
        return user;  
    }  
}

使用JdbcTemplate和RowMapper

import org.springframework.jdbc.core.JdbcTemplate;  
import org.springframework.jdbc.core.RowMapper;   
import java.util.List;  
// 假设jdbcTemplate已经被注入或创建  
JdbcTemplate jdbcTemplate = ...; // 获取JdbcTemplate实例  
String sql = "SELECT * FROM users";  
List<User> users = jdbcTemplate.query(sql, new UserRowMapper());   
for (User user : users) {  
    System.out.println(user);  
}

--Spring Data JPA:
Spring Data JPA是Spring Data项目的一部分,它提供了对JPA(Java Persistence API)的简化访问。
通过创建继承自JpaRepository或CrudRepository接口的接口,可以自动生成数据访问代码,实现基本的CRUD操作。
支持查询方法(Query Methods)的声明,允许开发者通过定义方法名来创建查询,而无需编写具体的SQL或JPQL。
--Spring Data MongoDB:
对于MongoDB数据库,Spring Data提供了类似的简化访问。
通过创建继承自MongoRepository的接口,可以自动生成对MongoDB的数据访问代码。
--Spring Data Redis:
对于Redis键值存储,Spring Data提供了操作模板和仓库支持。
允许开发者以声明式或编程式的方式与Redis进行交互。
--Spring Data Neo4j:
对于图数据库Neo4j,Spring Data也提供了支持。
--Spring Integration:
Spring Integration是一个轻量级的消息传递框架,用于在企业级应用中构建集成解决方案。
它支持多种消息传递中间件(如RabbitMQ、ActiveMQ、Kafka等)和传输协议(如JMS、AMQP、STOMP等)。
提供了消息通道(Channel)、消息端点(Endpoint)、消息转换器(Message Converter)等核心概念,以及一系列的消息处理器(如过滤器、路由器、转换器等)。
--Spring Batch:
Spring Batch是一个用于处理大量数据的批处理框架。
它提供了丰富的批处理功能,如作业(Job)管理、步骤(Step)定义、数据读取/写入、错误处理等。
支持各种数据源和输出目标,可以与其他Spring项目(如Spring Data)无缝集成。
--Spring for Apache Kafka:
Spring为Apache Kafka提供了支持,允许开发者以声明式或编程式的方式与Kafka进行交互。
提供了KafkaTemplate和KafkaListener等核心组件,以及一系列的消息处理器和序列化/反序列化工具。
--Spring Cloud Stream:
Spring Cloud Stream是Spring Cloud的一部分,用于构建基于消息的微服务应用。
它基于Spring Integration,并提供了对多种消息传递中间件(如RabbitMQ、Kafka等)的简化访问。
允许开发者通过定义输入和输出通道(Channel)来构建松耦合的微服务应用。

©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。
禁止转载,如需转载请通过简信或评论联系作者。

推荐阅读更多精彩内容