Spring

Published 2026-07-30 19:32 Updated 2026-10-13 17:14 2592 words 13 min read ... Page views AI-reviewed An AI proof-read this post, but it still deserves a careful read. AI-rewritten Someone else wrote the original; AI helped me rewrite and polish it.

AI-reviewed An AI proof-read this post, but it still deserves a careful read.

This article systematically introduces the core concepts, configuration methods, Bean life cycle, automatic assembly, cyclic dependency processing, annotation use, AOP proxy mechanism, and integration with MyB and transactions of Spring IoC and dependency injection. It focuses on the implementation of dependency injection through Setter or constructor, Bean scope and life cycle management, as well as automatic component registration and dependency injection through annotations and configuration classes, and combined with AOP to achieve decoupling and management of crosscutting concerns such as logging, transactions, etc. Finally, it demonstrates the integration practice of Spring and MyBatis, emphasizing that Spring can uniformly manage data sources, SqlSessionFactory and transactions, avoiding manual manipulation of database sessions.

Spring

IoC and Dependency Injection

The core idea of IoC

IoC is inversion of control. Traditional code usually creates dependent objects by the objects themselves; after using Spring, the creation, configuration, and dependencies of objects are managed uniformly by the Spring IoC container.

Dependency injection is a concrete implementation of IoC. Objects only declare what dependencies they need, and the container injects the corresponding objects into them when creating the Bean.

example,Driver dependent Vehicle。Business categories no longer execute themselves new Car(), but is created by containers Car, re-inject Driver。

public interface Vehicle {
    void run();
}

public class Car implements Vehicle {
    private String name;

    public void setName(String name) {
        this.name = name;
    }

    @Override
    public void run() {
        System.out.println(name + "正在行驶");
    }
}

public class Driver {
    private String name;
    private Vehicle vehicle;

    public void setName(String name) {
        this.name = name;
    }

    public void setVehicle(Vehicle vehicle) {
        this.vehicle = vehicle;
    }

    public void drive() {
        System.out.println(name + "准备出发");
        vehicle.run();
    }
}

Spring project construction

Creating the Maven Project

in pom.xml introduced in spring-context。The following versions only correspond to the original course example environment:

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>5.3.20</version>
</dependency>

Create a core configuration file

Create in the Resource Catalog applicationContext.xml。

<?xml version="1.0" encoding="UTF-8"?>
<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
           https://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

start the container

ApplicationContext context =
        new ClassPathXmlApplicationContext("applicationContext.xml");

Driver driver = context.getBean("driver", Driver.class);
driver.drive();

XML Configuration Bean

Register Bean

<bean id="driver" class="com.hyxy.Driver"/>
<bean id="car" class="com.hyxy.Car"/>

id is the name of the Bean in the container,class Is the fully qualified class name of the implementation class.

Setter injection

<bean id="car" class="com.hyxy.Car">
    <property name="name" value="小轿车"/>
</bean>

<bean id="driver" class="com.hyxy.Driver">
    <property name="name" value="老张"/>
    <property name="vehicle" ref="car"/>
</bean>

value Used to inject simple values,ref Used to reference another Bean in the container.

Setter injection requires that the property have a corresponding Setter method. The Getter method is not necessary to complete the injection, but it is usually provided in accordance with the JavaBean specification.

constructor injection

public class Driver {
    private final String name;
    private final Vehicle vehicle;

    public Driver(String name, Vehicle vehicle) {
        this.name = name;
        this.vehicle = vehicle;
    }
}
<bean id="driver" class="com.hyxy.Driver">
    <constructor-arg index="0" value="老张"/>
    <constructor-arg index="1" ref="car"/>
</bean>

can also name or type Specify parameters, but when the constructor is overloaded, use the index Or explicit parameter names make it easier to avoid ambiguity.

Constructor injection is suitable for necessary dependencies to ensure that the object remains available after creation is complete.

Bean scope

Spring beans are singleton scope by default, that is, in the same container, only one instance is usually created by the same Bean definition.

<bean id="driver" class="com.hyxy.Driver" scope="singleton"/>

The prototype scope creates a new object each time a Bean is fetched:

<bean id="driver" class="com.hyxy.Driver" scope="prototype"/>

Common scopes include:

scopemeaning
singletonThere is usually only one instance in each Spring container.
prototypeCreate a new instance each time you retrieve it.
requestOne instance for each HTTP request.
sessionOne instance for each HTTP Session.
applicationOne instance for each Web application.

Web scopes need to be used in the context of a Web application.

automatic assembly

XML Assemble by name

<bean id="driver"
      class="com.hyxy.Driver"
      autowire="byName">
    <property name="name" value="老张"/>
</bean>

<bean id="vehicle" class="com.hyxy.Car">
    <property name="name" value="小轿车"/>
</bean>

byName Beans with the same name are found based on the property name. Requirements in the above example Driver The attribute name of is vehicle。

XML Assemble by Type

<bean id="driver"
      class="com.hyxy.Driver"
      autowire="byType">
    <property name="name" value="老张"/>
</bean>

<bean id="car" class="com.hyxy.Car"/>

byType Beans are found based on property types. If there are multiple candidates of the same type, the container cannot determine the unique dependence and usually throws an exception.

Automatic assembly of XML can be used to learn principles, but actual projects more often use constructors to inject matching annotations or Java configurations.

circular dependency

Circular dependence refers to the mutual dependence between beans, such as A dependent B, at the same time B turn, relies A。

Spring can resolve Setter or field injection cyclic dependencies for some singleton beans, but cannot guarantee that all cyclic dependencies are resolved. The following situations are usually not resolved automatically:

  • Constructors depend on each other.
  • prototype Circular dependence between beans.
  • Circular dependencies caused by certain agents, initialization procedures, or custom life cycle logic.

Circular dependence usually reflects the unreasonable division of class responsibilities, which should be solved first by redesigning dependence relationships rather than relying on containers to cover the bottom.

Bean life cycle

XML lifecycle approach

<bean id="driver"
      class="com.hyxy.Driver"
      init-method="init"
      destroy-method="destroy"/>
public class Driver {
    public void init() {
        System.out.println("初始化 Driver");
    }

    public void destroy() {
        System.out.println("销毁 Driver");
    }
}

The singleton Bean’s destruction callback is called when the container is closed. Spring does not automatically and completely manage the destruction process of prototype beans, and the caller is usually responsible for cleaning up resources after the prototype object is used.

Annotate life cycle method

Use of Spring 5 common projects javax.annotationSpring 6 and Spring Boot 3 jakarta.annotation。

@PostConstruct
public void init() {
    System.out.println("初始化 Driver");
}

@PreDestroy
public void destroy() {
    System.out.println("销毁 Driver");
}

Overview of the initialization process

A typical initialization process for a singleton Bean can be summarized as:

  1. Instantiate the Bean.

  2. Inject attributes and dependencies.

  3. invoking the relevant Aware Interface.

  4. implementation BeanPostProcessor Pre-processing of.

  5. Perform an initialization callback, such as @PostConstruct、InitializingBean or custom init-method。

  6. implementation BeanPostProcessor , AOP proxies are usually created at this stage.

  7. Bean becomes available.

When the container is closed, a corresponding destruction callback is executed.

BeanFactory with FactoryBean

BeanFactory

BeanFactory It is the basic interface of the Spring IoC container and is responsible for the creation, acquisition and dependency management of beans.ApplicationContext On this basis, functions such as event, internationalization, and resource loading have been added.

FactoryBean

FactoryBean<T> It is a Bean itself, but what the caller obtains through the ordinary Bean name is usually the object it produces.

public class SqlSessionFactoryBean implements FactoryBean<SqlSessionFactory> {
    private String configLocation;

    public void setConfigLocation(String configLocation) {
        this.configLocation = configLocation;
    }

    @Override
    public SqlSessionFactory getObject() throws Exception {
        try (InputStream inputStream =
                     Resources.getResourceAsStream(configLocation)) {
            return new SqlSessionFactoryBuilder().build(inputStream);
        }
    }

    @Override
    public Class<?> getObjectType() {
        return SqlSessionFactory.class;
    }

    @Override
    public boolean isSingleton() {
        return true;
    }
}
<bean id="sqlSessionFactory"
      class="com.hyxy.SqlSessionFactoryBean">
    <property name="configLocation" value="mybatis-config.xml"/>
</bean>

obtain sqlSessionFactory What you get when you FactoryBean Produced object; to get the factory Bean itself, you need to add &。

Bean registration method

Common Bean registration methods for Spring include XML, component scanning, and Java configuration.

XML registration

<bean id="car" class="com.hyxy.Car"/>

XML is suitable for centralized viewing of configuration and is also convenient for registering third-party classes whose source code cannot be modified. However, it will be cumbersome when the configuration volume is large.

Annotations and component scanning

Start scanning in the configuration file first:

<context:component-scan base-package="com.hyxy"/>

Then mark the class with component annotations:

@Component
public class Car {
}

Common hierarchical annotations include:

  • @Controller: Control layer components.
  • @Service: Business layer components.
  • @Repository: Data access layer components.
  • @Component: Common components.

These annotations can all register classes as Spring Beans, and hierarchical names are mainly used to express responsibilities; some annotations may also participate in mechanisms such as exception conversions in the framework.

Dependency injection annotation

@Autowired

@Autowired Find dependencies mainly by type. If there are multiple beans of the same type, you can combine @Qualifier or @Primary Eliminate ambiguity.

It is recommended to use constructor injection:

@Service
public class DriverService {
    private final Vehicle vehicle;

    public DriverService(@Qualifier("car") Vehicle vehicle) {
        this.vehicle = vehicle;
    }
}

When there is only one constructor, you can usually omit the @Autowired。

@Qualifier

@Component("car")
public class Car implements Vehicle {
}

@Component("bus")
public class Bus implements Vehicle {
}
@Service
public class DriverService {
    private final Vehicle vehicle;

    public DriverService(@Qualifier("bus") Vehicle vehicle) {
        this.vehicle = vehicle;
    }
}

@Primary

@Component
@Primary
public class Car implements Vehicle {
}

When there are multiple candidate beans of the same type,@Primary Marked beans will be the default selection.

@Resource

@Resource Belonging to Jakarta or Java standard annotations, usually matching by name first and then by type. it can name Explicitly specify the Bean name.

@Resource(name = "car")
private Vehicle vehicle;

@Value

@Value Simple configuration values or Spring expressions can be injected.

@Value("${car.name:默认车辆}")
private String carName;

Complex configuration objects are more suitable for use @ConfigurationProperties。

@Scope

@Component
@Scope("prototype")
public class Driver {
}

Java config

Define configuration classes

@Configuration
public class MyConfig {
    @Bean
    public Car car() {
        Car car = new Car();
        car.setName("小轿车");
        return car;
    }

    @Bean
    @Scope("prototype")
    public Driver driver(Car car) {
        Driver driver = new Driver();
        driver.setName("老张");
        driver.setVehicle(car);
        return driver;
    }
}

@Configuration Indicates that this class is a configuration class,@Bean The return object of the method is registered in the container. Method parameters are automatically injected by the container.

Expressing dependencies through method parameters is better than directly calling others within a method @Bean The method is clearer and easier to test.

Launch the Java configuration container

ApplicationContext context =
        new AnnotationConfigApplicationContext(MyConfig.class);

Driver driver = context.getBean(Driver.class);
driver.drive();

proxy mode

The proxy pattern includes target objects, proxy objects, and abstract contracts that both parties follow. The proxy object adds common logic before and after calling the target method, such as logging, permission verification, or transaction management.

static agent

public interface HouseService {
    void rentHouse();
}

public class Owner implements HouseService {
    @Override
    public void rentHouse() {
        System.out.println("签合同并收款");
    }
}

public class Agent implements HouseService {
    private final HouseService target;

    public Agent(HouseService target) {
        this.target = target;
    }

    @Override
    public void rentHouse() {
        System.out.println("寻找房源并协商价格");
        target.rentHouse();
    }
}

Static proxies need to write corresponding proxy classes for different target types, and there are many duplicate codes.

JDK dynamic proxies

JDK dynamic proxy creates proxy objects based on interfaces.

HouseService target = new Owner();

HouseService proxy = (HouseService) Proxy.newProxyInstance(
        target.getClass().getClassLoader(),
        target.getClass().getInterfaces(),
        (proxyObject, method, args) -> {
            System.out.println("调用前处理");
            try {
                return method.invoke(target, args);
            } finally {
                System.out.println("调用后处理");
            }
        }
);

proxy.rentHouse();

CGLIB dynamic agent

CGLIB creates a proxy by generating a subclass of the target class and does not require the target class to implement an interface. Target class cannot be final, the method that requires an agent cannot be final。

public class DaoMethodInterceptor implements MethodInterceptor {
    @Override
    public Object intercept(
            Object proxy,
            Method method,
            Object[] args,
            MethodProxy methodProxy) throws Throwable {
        System.out.println("开启事务");
        try {
            Object result = methodProxy.invokeSuper(proxy, args);
            System.out.println("提交事务");
            return result;
        } catch (Throwable e) {
            System.out.println("回滚事务");
            throw e;
        }
    }
}
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(EmpDao.class);
enhancer.setCallback(new DaoMethodInterceptor());

EmpDao empDao = (EmpDao) enhancer.create();
empDao.save();

Don’t use outdated ones Class.newInstance()。When you need to create an object through reflection, you should use the getDeclaredConstructor().newInstance()。

AOP

AOP is area-oriented programming that is used to separate crosscutting logic such as logging, transactions, and permissions from business code.

common terms

  • Connection point: A location in program execution that can be enhanced, such as method invocations.
  • Entry points: Used to filter connection points that need to be enhanced.
  • Notification: Enhancement logic executed before and after the target method.
  • Aspect: A combination of entry points and notifications.
  • Target object: The enhanced business object.
  • Proxy object: The object after application of enhanced logic.

Introduce dependence

<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-aspects</artifactId>
    <version>5.3.20</version>
</dependency>

Define the cut plane

@Aspect
@Component
public class LogAspect {
    @Pointcut("execution(* com.hyxy.service..*(..))")
    public void serviceMethod() {
    }

    @Before("serviceMethod()")
    public void before() {
        System.out.println("执行方法前记录日志");
    }

    @AfterReturning(pointcut = "serviceMethod()", returning = "result")
    public void afterReturning(Object result) {
        System.out.println("方法正常返回:" + result);
    }

    @AfterThrowing(pointcut = "serviceMethod()", throwing = "exception")
    public void afterThrowing(Throwable exception) {
        System.out.println("方法发生异常:" + exception.getMessage());
    }

    @After("serviceMethod()")
    public void after() {
        System.out.println("方法结束");
    }
}

Open annotation AOP:

<aop:aspectj-autoproxy/>

@After similar finally, will be executed whether the method returns normally or throws an exception; it will only be executed when it returns normally @AfterReturning。

Overview of Spring transactions

Spring declarative transactions are based on AOP. Common transaction attributes include propagation behavior, isolation levels, timeouts, read-only, and rollback rules.

Common communication behaviors:

communication behaviormeaning
REQUIREDJoin if there are transactions, and create if there are no transactions.
REQUIRES_NEWAlways create a new transaction and pause the current transaction.
SUPPORTSIf there is a transaction, join, and if there is no transaction, it will run non-transactional.
NESTEDUse nested transaction scopes in environments that support savepoints.
@Service
public class UserService {
    @Transactional(rollbackFor = Exception.class)
    public void saveUser(User user) throws Exception {
        // 数据库操作
    }
}

By default, Spring sets RuntimeException and Error Rollback. Ordinary detected exceptions are not automatically rolled back. When you need to roll back a detected exception, you should configure rollbackFor。

Spring integrates with MyBatis

The integration goal is to have Spring manage data sources,SqlSessionFactory, Mapper Agents and Transactions.

Maven Depends

The following versions are examples of the original course combinations:

<properties>
    <maven.compiler.source>11</maven.compiler.source>
    <maven.compiler.target>11</maven.compiler.target>
    <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<dependencies>
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>5.3.20</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>5.3.20</version>
    </dependency>

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-tx</artifactId>
        <version>5.3.20</version>
    </dependency>

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.1</version>
    </dependency>

    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>2.0.7</version>
    </dependency>

    <dependency>
        <groupId>com.mysql</groupId>
        <artifactId>mysql-connector-j</artifactId>
        <version>8.0.33</version>
    </dependency>

    <dependency>
        <groupId>com.alibaba</groupId>
        <artifactId>druid</artifactId>
        <version>1.2.23</version>
    </dependency>
</dependencies>

database configuration

jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/java2601?serverTimezone=UTC&characterEncoding=utf8
jdbc.username=root
jdbc.password=root
jdbc.maxActive=300
jdbc.initialSize=2
jdbc.maxWait=60000
jdbc.minIdle=1

Spring configuration

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:context="http://www.springframework.org/schema/context"
       xmlns:tx="http://www.springframework.org/schema/tx"
       xmlns:mybatis-spring="http://mybatis.org/schema/mybatis-spring"
       xsi:schemaLocation="
           http://www.springframework.org/schema/beans
           https://www.springframework.org/schema/beans/spring-beans.xsd
           http://www.springframework.org/schema/context
           https://www.springframework.org/schema/context/spring-context.xsd
           http://www.springframework.org/schema/tx
           https://www.springframework.org/schema/tx/spring-tx.xsd
           http://mybatis.org/schema/mybatis-spring
           http://mybatis.org/schema/mybatis-spring.xsd">

    <context:property-placeholder location="classpath:db.properties"/>
    <context:component-scan base-package="com.hyxy"/>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="maxActive" value="${jdbc.maxActive}"/>
        <property name="initialSize" value="${jdbc.initialSize}"/>
        <property name="maxWait" value="${jdbc.maxWait}"/>
        <property name="minIdle" value="${jdbc.minIdle}"/>
    </bean>

    <bean id="sqlSessionFactory"
          class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="mapperLocations"
                  value="classpath*:com/hyxy/mapper/*.xml"/>
        <property name="typeAliasesPackage" value="com.hyxy.po"/>
    </bean>

    <mybatis-spring:scan base-package="com.hyxy.mapper"/>

    <bean id="transactionManager"
          class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
        <property name="dataSource" ref="dataSource"/>
    </bean>

    <tx:annotation-driven transaction-manager="transactionManager"/>
</beans>

SqlSessionFactoryBean responsible for creating MyBatis SqlSessionFactory, Mapper scanner creates a proxy for the interface and registers it with the Spring container.

Mapper and Service

public interface UserMapper {
    int insert(User user);
}
@Service
public class UserService {
    private final UserMapper userMapper;

    public UserService(UserMapper userMapper) {
        this.userMapper = userMapper;
    }

    @Transactional(rollbackFor = Exception.class)
    public void save(User user) throws Exception {
        userMapper.insert(user);
    }
}

The business layer only needs to inject Mapper and should not create it by itself SqlSession。When transactions are managed by Spring, they should not be called manually in Mapper or Service commit()。

Written by AI-rewritten

If you enjoyed this, leave a comment~

Loading...