Spring core container - from configuration files to annotation development & creation of objects + member variable assignment & enhancement methods

Table of contents

lead out


Spring can create new objects, assign values ​​to member variables, and enhance methods;

insert image description hereinsert image description here

Spring entry case

Getting to know Spring

image-20221104142926403

What spring can do:
(1) new object, put it in the spring container;
(2) inject member variables, dependency injection, inversion of control;
(3) enhance method

insert image description here

insert image description here

Getting Started Case 1 - Implementing Druid + JDBCTemplate + dao with configuration files

1. The previous method: new object

package com.tianju;

import com.alibaba.druid.pool.DruidDataSource;
import com.tianju.dao.UserDaoImpl;
import com.tianju.entity.User;
import org.springframework.jdbc.core.JdbcTemplate;

import java.util.List;

/**
 * 之前的方式,new对象,建立连接,拿到JDBCTemplate,然后dao层使用,到service,到servlet
 */
public class DemoDaoImpl {
    
    
    public static void main(String[] args) {
    
    
        // Druid
        DruidDataSource druidDataSource = new DruidDataSource();
        druidDataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        druidDataSource.setUrl("jdbc:mysql://127.0.0.1:3306/javaweb?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true");
        druidDataSource.setUsername("root");
        druidDataSource.setPassword("123");
        druidDataSource.setMaxActive(10);
        
        // JDBCTemplate
        JdbcTemplate jdbcTemplate = new JdbcTemplate();
        jdbcTemplate.setDataSource(druidDataSource);

        // dao
        UserDaoImpl userDao = new UserDaoImpl();
        userDao.setJdbcTemplate(jdbcTemplate);
        List<User> list = userDao.queryAll();
        System.out.println(list);

    }
}

2. Use the configuration file method to hand over the new object to Spring

(1) configuration file

insert image description here

Configuration file template:

<?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
        http://www.springframework.org/schema/beans/spring-beans.xsd">
</beans>

beans.xml file

<?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
        http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    首先配置druid-->
<!--    id: ac.getBean("jdbcTemplate");用来从spring的容器中获取对象;
        class:交给spring来new的对象,两种情况:
                (1)自己写的类;
                (2)其他人写的类:
                <bean id="xxx" class="com.alibaba.druid.pool.DruidDataSource">
-->
<!--    TODO:替换:DruidDataSource druidDataSource = new DruidDataSource();-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<!--        spring给成员变量赋值-->
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
<!--        这里的url 需要在 & 符号后面加 amp; -->
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/javaweb?useSSL=false&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123"></property>
    </bean>

<!--    TODO:把JDBC也交给spring:JdbcTemplate jdbcTemplate = new JdbcTemplate(); jdbcTemplate.setDataSource(druidDataSource);-->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<!--       给成员变量赋值,即jdbcTemplate.setDataSource(druidDataSource)-->
<!--       给成员变量赋值的两种方式:
            (1)直接设置value:<property name="password" value="123"></property>
            (2)通过id引用xml文件中的 ref:<property name="dataSource" ref="dataSource"></property>
            -->
        <property name="dataSource" ref="dataSource"></property>
    </bean>

<!--    TODO:把dao也交给spring:UserDaoImpl userDao = new UserDaoImpl();userDao.setJdbcTemplate(jdbcTemplate);-->
    <bean id="userDao" class="com.tianju.dao.impl.UserDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>
</beans>

3. If you want to use an object, get ac.getBean("userDao"); from the spring container;

package com.tianju.test;

import com.tianju.dao.IUserDao;
import com.tianju.entity.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

/**
 * 用户测试spring配置的是否好用
 */
public class JDBCTestDemo {
    
    
    public static void main(String[] args) {
    
    
        // TODO:直接从spring容器中获取dao
//        ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
        IUserDao userDaoImpl = (IUserDao) ac.getBean("userDao");
        List<User> userList = userDaoImpl.queryAll();
        userList.forEach(System.out::println);

    }
}

insert image description here

4. The code of the entity class and the dao layer – Question: What if the interface has two implementation classes?

User.java file

package com.tianju.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;

/**
 * 用户登陆的实体类
 */
@Data //包括get,set,toString
@NoArgsConstructor
@AllArgsConstructor
public class User {
    
    
    private Integer id;
    private String username;
    private String password;
    private String nickname;
    private Date createTime;
    private Date updateTime;
    private String imgUrl;
}

IUserDao.java interface file

package com.tianju.dao;

import com.tianju.entity.User;

import java.util.List;

public interface IUserDao {
    
    
    List<User> queryAll();
}

UserDaoImpl.java implementation class file

package com.tianju.dao.impl;

import com.tianju.dao.IUserDao;
import com.tianju.entity.User;
import org.springframework.jdbc.core.BeanPropertyRowMapper;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.jdbc.core.RowMapper;

import java.util.List;

/**
 * UserDao的实现类
 */
public class UserDaoImpl implements IUserDao {
    
    
    private JdbcTemplate jdbcTemplate;

    /**
     * set方法,用于给这个jdbcTemplate设置druidDataSource,
     * 从而可以使用这个jdbcTemplate
     * @param jdbcTemplate
     */
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
    
    
        this.jdbcTemplate = jdbcTemplate;
    }

    @Override
    public List<User> queryAll() {
    
    
        RowMapper<User> rowMapper = new BeanPropertyRowMapper<>(User.class);
        return jdbcTemplate.query("SELECT * FROM user_tab", rowMapper );
    }
}

[Supplement] Two ways to get objects in the spring container: id or object type

(1) Obtained by id, id is unique in the xml configuration file: there will be no problem;

If the id is repeated, an error will be reported:

Exception in thread “main” org.springframework.beans.factory.parsing.BeanDefinitionParsingException: Configuration problem:

Bean name ‘userDao’ is already used in this beans> element
Offending resource: class path resource [beans.xml]

IUserDao userDaoImpl = (IUserDao) ac.getBean("userDao");

(2) Acquired by the type of the class:

IUserDao userDaoImpl = ac.getBean(IUserDao.class);

At this time, if the interface has two implementation classes, an exception will occur. Spring does not know which of the two objects in the container should be taken, and an error will be reported:

No qualifying bean of type ‘com.tianju.dao.IUserDao’ available: expected single matching bean but found 2: userDao,userDao1

Introductory case 2----person entity class understands the configuration file

insert image description here

person.java entity class file

package com.tianju.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Person {
    
    
    private Integer id;
    private String name;
    private Date birthday;

    public void init(){
    
    
        // 每次new出来都执行该方法
        System.out.println("每次new person对象时都执行的方法");
    }

    public void destroy(){
    
    
        // 在spring容器销毁时执行该方法
        System.out.println("spring容器销毁时执行的方法");
    }
}

(1) Initial situation: when the spring program reads this line, it creates a person class, puts it in the spring container, and its id is person;

<bean id="person" class="com.tianju.entity.Person" scope="singleton">

(2) Parameter scope="singleton" singleton, scope="prototype" non-singleton:

Regardless of whether it is a singleton or not, the init-method method will be executed;

If it is a singleton "singleton", the destroy method will be executed when the container is closed;

If it is not a singleton "prototype", the destroy method will not be executed when the container is closed;

<bean id="person" class="com.tianju.entity.Person" scope="singleton" init-method="init" destroy-method="destroy">

In singleton mode, the same object is obtained from the container; == is true;

In non-singleton mode, the object obtained from the container is not the same object; == is false;

(3) Ways to assign values ​​to member variables + dependency injection

Assign values ​​to member variables: (1) through the constructor constructor-arg; (2) assign properties through attributes;

There are two ways of assignment: (1) direct assignment of value; (2) dependency injection ref;

insert image description here

Assignment via constructor:

<!--    TODO:当spring程序读到这一行时,就创建了一个person类,id赋值为person,放到spring的容器中
        scope="singleton" 默认是单例:scope="prototype"
-->
    <bean id="person" class="com.tianju.entity.Person" scope="prototype" init-method="init" destroy-method="destroy">
<!--        有两种给成员变量赋值的方式,(1)构造函数;(2)通过属性赋值-->
        <constructor-arg name="id" value="100"></constructor-arg>
        <constructor-arg name="name" value="peter"></constructor-arg>
<!--        -->
        <constructor-arg name="birthday" ref="date"></constructor-arg>
    </bean>

<!--    依赖注入-->
    <bean id="date" class="java.util.Date"></bean>

Assign property by attribute:

    <bean id="person" class="com.tianju.entity.Person" scope="prototype" init-method="init" destroy-method="destroy">
<!--        有两种给成员变量赋值的方式,(1)构造函数;(2)通过属性赋值-->
        <property name="id" value="1"></property>
        <property name="name" value="peter"></property>
        <property name="birthday" ref="date"></property>

    </bean>

<!--    依赖注入-->
    <bean id="date" class="java.util.Date"></bean>

(4) Test file execution sequence, new spring container – read bean.xml file...

package com.tianju.test;

import com.tianju.entity.Person;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class PersonTestDemo {
    
    
    public static void main(String[] args) {
    
    
        // 1.new ClassPathXmlApplicationContext spring创建了一个容器,用来放对象;
        // 2.读取bean.xml文件,如果配置了bean标签,就生成配置的对象,Person对象;
        // 3.把对象放到容器中,给成员变量赋值;
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
        // 4.从容器中通过id获取对象;
        Person person = (Person)ac.getBean("person");
        // 5.从容器中通过类名获取对象;
        Person person1 = ac.getBean(Person.class);
        System.out.println("是否是同一个对象:"+(person1==person));

        // 关闭容器
        ac.close();
    }
}

Spring creates new objects + assigns values ​​​​to member variables—from configuration files to annotation development

insert image description here
insert image description here

Realize controller ≈ servlet with configuration file

1. Guide package – implement version control with spring.verson

insert image description here

<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>

    <groupId>com.tianju</groupId>
    <artifactId>spring0615</artifactId>
    <version>1.0-SNAPSHOT</version>

    <properties>
        <maven.compiler.source>8</maven.compiler.source>
        <maven.compiler.target>8</maven.compiler.target>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<!--        进行spring的版本控制-->
        <spring.version>5.2.22.RELEASE</spring.version>
    </properties>

    <dependencies>
<!--        spring 的包,spring的容器,上下文,代表这个spring项目-->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.20</version>
        </dependency>

        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.2.16</version>
        </dependency>

        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>${spring.version}</version>
        </dependency>

        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.22</version>
        </dependency>
    </dependencies>
</project>

2. Configuration file writing 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
        http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/javaweb?useSSL=false&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123"></property>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

    <bean id="userDao" class="com.tianju.dao.impl.UserDaoImpl">
        <property name="jdbcTemplate" ref="jdbcTemplate"></property>
    </bean>

    <bean id="userService" class="com.tianju.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"></property>
    </bean>

    <bean id="userController" class="com.tianju.controller.UserController">
        <property name="userService" ref="userService"></property>
    </bean>
</beans>

3. Test ClassPathXmlApplicationContext

package com.tianju.test;

import com.tianju.controller.UserController;
import com.tianju.entity.User;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class TestXMLDemo {
    
    
    public static void main(String[] args) {
    
    
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserController userController = (UserController) ac.getBean("userController");
        List<User> userList = userController.queryAll();
        userList.forEach(System.out::println);
    }
}

Realize the controller with annotations

insert image description here

1. Update context:component-scan of configuration file xml

If @Component(@Repository @Service @Controller) is marked on the class, Spring will create a new class, put it in the container, and @Autowired will automatically inject the value

<?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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">

<!--    从com.tianju包下,扫描所有的类,
    如果类上面标注了@Component(@Repository @Service @Controller) Spring就会new类,放容器中,
    @Autowired 自动注入值-->
    <context:component-scan base-package="com.tianju"></context:component-scan>

    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://127.0.0.1:3306/javaweb?useSSL=false&amp;serverTimezone=Asia/Shanghai&amp;allowPublicKeyRetrieval=true"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123"></property>
    </bean>

    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
        <property name="dataSource" ref="dataSource"></property>
    </bean>

</beans>

2. Annotate @Component(@Repository @Service @Controller) + @Autowired on dao, service, and controller

insert image description here

Such as Controller.java file

package com.tianju.controller;

import com.tianju.entity.User;
import com.tianju.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import java.util.List;

/**
 * 现阶段就当是servlet
 */
@Controller
public class UserController {
    
    
    @Autowired
    IUserService userService;

    public void setUserService(IUserService userService) {
    
    
        this.userService = userService;
    }

    public List<User> queryAll(){
    
    
        return userService.queryAll();
    }
}

3. Test ClassPathXmlApplicationContext

package com.tianju.test;

import com.tianju.controller.UserController;
import com.tianju.entity.User;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import java.util.List;

public class TestControllerDemo {
    
    
    public static void main(String[] args) {
    
    
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
        UserController userController = (UserController) ac.getBean("userController");
        List<User> userList = userController.queryAll();
        userList.forEach(System.out::println);
    }
}

Replace the xml configuration file under resource with the SpringConfig.java file

insert image description here

3. Replace the xml configuration file under resource with SpringConfig.java file @Configuration @ComponentScan @Bean

Main points:

  • 1. How to tell spring that this file is to replace the configuration xml file; @Configuration
  • 2. How to replace context:component-scan in the xml file to know which packages to scan; @ComponentScan(“com.tianju”)

In order to replace the xml configuration file, you also need

  • 1. put the dataSource in the container;
  • 2. Put the jdbcTemplate in the container;
  • If @Bean is added to a method, the return value of this method is in the container; the method name is id;

If a method depends on other methods, then

  • If a method depends on the object in the container, write the object name in the parameter of the method,
  • Spring will inject the dataSource in the container into the method
package com.tianju.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;

/**
 * 用来代替resources中的配置xml文件:
 * 1.如何告诉spring,这个文件是代替配置xml文件;@Configuration
 * 2.如何代替xml文件中context:component-scan,知道扫描哪些包;@ComponentScan("com.tianju")
 */
@Configuration
@ComponentScan("com.tianju")
public class SpringConfig {
    
    
    /**
     * 要想实现代替xml配置文件,则还需要
     * 1.dataSource放到容器中;
     * 2.jdbcTemplate放到容器中;
     * 如果一个方法上加了@Bean,这个方法的返回值就在容器中了;方法名 就是id;
     */
    @Bean
    public DataSource dataSource(){
    
    
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.cj.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://127.0.0.1:3306/javaweb?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true");
        dataSource.setUsername("root");
        dataSource.setPassword("123");
        return dataSource;
    }

    /**
     * 如果一个方法依赖了容器中的对象,在该方法的参数中写这个对象名,
     * spring会把容器中的dataSource注入到方法中
     * @param dataSource 从容器中根据id获取 DataSource
     * @return
     */
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource){
    
    
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }

}

4. Test AnnotationConfigApplicationContext

package com.tianju.test;

import com.tianju.config.SpringConfig;
import com.tianju.controller.UserController;
import com.tianju.entity.User;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.Arrays;
import java.util.List;

/**
 * 测试配置文件SpringConfig.java
 */
public class TestConfigDemo1 {
    
    
    public static void main(String[] args) {
    
    
        // 用java的config文件,代替配置文件xml
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
        // 获取所有bean的名字
        String[] beanDefinitionNames = ac.getBeanDefinitionNames();
        System.out.println(Arrays.toString(beanDefinitionNames));
        UserController userController = ac.getBean(UserController.class);
        List<User> list = userController.queryAll();
        list.forEach(System.out::println);
    }
}

The SpringCofig.java file introduces the properties file—decoupling druid + introducing other config.java

insert image description here

insert image description here

1. Introduce the jdbc.properties configuration file @PropertySource("classpath:jdbc.properties")+@Value("${jdbc.url}")

In the above method, jdbc is coupled to the java code. If there is a jdbc.properties file related to jdbc configuration under resources, how to read the configuration file in the springConfig.java file?

jdbc.properties file

jdbc.driverClassName=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://127.0.0.1:3306/javaweb?useSSL=false&serverTimezone=Asia/Shanghai&allowPublicKeyRetrieval=true
jdbc.username=root
jdbc.password=123

The updated SpringConfig.java file

package com.tianju.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.PropertySource;
import org.springframework.jdbc.core.JdbcTemplate;

import javax.sql.DataSource;
/**
 * 用来代替resources中的配置xml文件
 * 注解 @Configuration表示是spring的配置类,用来代替 applicationContext.xml文件的;
 * 注解 @ComponentScan("com.tianju") 用来代替 <context:component-scan base-package="com.tianju"></context:component-scan>;
 */

@Configuration
@ComponentScan("com.tianju")
// TODO:如果想把jsbc用配置文件弄出来
// 引入其他的配置文件
@PropertySource("classpath:jdbc.properties")
public class SpringConfig {
    
    

    @Value("${jdbc.driverClassName}")
    private String diverClassName;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String username;
    @Value("${jdbc.password}")
    private String password;
    /**
     * 要想实现代替xml配置文件,则还需要
     * 1.dataSource放到容器中;
     * 2.jdbcTemplate放到容器中;
     * 如果一个方法上加了@Bean,这个方法的返回值就在容器中了;方法名 就是id;
     */
    @Bean
    public DataSource dataSource(){
    
    
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName(diverClassName);
        dataSource.setUrl(url);
        dataSource.setUsername(username);
        dataSource.setPassword(password);
        return dataSource;
    }

    /**
     * 如果一个方法依赖了容器中的对象,在该方法的参数中写这个对象名,
     * spring会把容器中的dataSource注入到方法中
     * @param dataSource 从容器中根据id获取 DataSource
     * @return
     */
    @Bean
    public JdbcTemplate jdbcTemplate(DataSource dataSource){
    
    
        JdbcTemplate jdbcTemplate = new JdbcTemplate(dataSource);
        jdbcTemplate.setDataSource(dataSource);
        return jdbcTemplate;
    }
}

For testing AnnotationConfigApplicationContext

package com.tianju.test;

import com.tianju.config.SpringConfig;
import com.tianju.controller.UserController;
import com.tianju.entity.User;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import java.util.List;

public class TestPropertiesDemo1 {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserController userController = ac.getBean(UserController.class);
        List<User> userList = userController.queryAll();
        userList.forEach(System.out::println);
    }
}

2. Introduce other config.java files @Import(SpringConfig.class)

package com.tianju.config;

import org.springframework.context.annotation.Import;

/**
 * 引入其他配置文件 @Import(SpringConfig.class)
 */
@Import(SpringConfig.class)
public class SConfig {
    
    
}

Configuration single case/multiple cases, initialization method, destruction method

insert image description here

  • Note: When @Controller scans, if it finds this sentence, the new object will come out;

代替 bean id=“userController” class=“com.tianju.controller.UserController”>

  • id: By default, lowercase letters are not written. If you specify it yourself, use @Controller("userController")

  • Singleton: The default is a singleton; if you want to set it not a singleton, then @Scope(value = "PROTOTYPE")

  • Initialization method: @PostConstruct: run after the constructor

  • Destruction method: @PreDestroy; execute before the container is destroyed; execute singleton ac.close();

  • Annotation: @Autowired, used instead of property name="userService" ref="userService">/property>

1.@Scope(value = “singleton”) prototype + @PostConstruct + @PreDestroy

Entity class Person.java code

package com.tianju.entity;

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import java.util.Date;
@Data
@NoArgsConstructor
@AllArgsConstructor

@Component
@Scope(value = "singleton") // singleton prototype
public class Person {
    
    
    private Integer id;
    private String name;
    private Date birthday;

    @PostConstruct
    public void init(){
    
    
        // 每次new出来都执行该方法
        System.out.println("每次new person对象时都执行的方法");
    }

    @PreDestroy
    public void destroy(){
    
    
        // 在spring容器销毁时执行该方法
        System.out.println("spring容器销毁时执行的方法");
    }
}

2. Configuration file @Configuration @ComponentScan("com.tianju") + test AnnotationConfigApplicationContext

Configuration file SpringConfig.java file

package com.tianju.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration
@ComponentScan("com.tianju")
public class SpringConfig {
    
    
}

test file

package com.tianju.test;

import com.tianju.config.SpringConfig;
import com.tianju.entity.Person;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class SpringConfigTest {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
        Person person = ac.getBean(Person.class);
        System.out.println(person);
        ac.close();
    }
}

If an interface has two implementing classes - the problem with the starter case

insert image description here

When injecting: 1. According to the type of injection, look for the implementation class of IUserService to inject into it;

  • 2. Solution 1: If there are multiple implementation classes, find the corresponding implementation class in the container according to the id of the variable name; or solve according to 3
  • 3. Solution 2: Unexpected situation: If the variable name does not want to be changed, what should I do? It can be specified with @Qualifier("userServiceImp1");
  • 4. Scheme 3: Use an annotation @Resource(name = "userServiceImpl1"), which can be injected or specified, instead of @Autowired and @Qualifier("userServiceImpl1");
  • Supplement: @Autowired is developed by spring; @Resource is java itself;

1. Option 1: Specify the name—designate one of the implementation classes userServiceImpl

package com.tianju.controller;

import com.tianju.entity.User;
import com.tianju.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

import java.util.List;

/**
 * 现阶段就当是servlet
 */
@Controller
public class UserController {
    
    
    @Autowired
    IUserService userServiceImpl;

    // 如果上面标注了 @Autowired, 下面就不用写了
    public void setUserService(IUserService userService) {
    
    
        this.userServiceImpl = userService;
    }

    public List<User> queryAll(){
    
    
        return userServiceImpl.queryAll();
    }
}

2. Solution 2: specify with annotation @Qualifier("userServiceImp2") + @Autowired

package com.tianju.controller;

import com.tianju.entity.User;
import com.tianju.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

import java.util.List;

/**
 * 现阶段就当是servlet
 */
@Controller

public class UserController {
    
    
    
    @Autowired
    @Qualifier("userServiceImpl2")
    IUserService userService;

    public List<User> queryAll(){
    
    
        return userService.queryAll();
    }
}

3. Solution 3: Replace the above two with an annotation @Resource(name = "userServiceImpl")

package com.tianju.controller;

import com.tianju.entity.User;
import com.tianju.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;
import java.util.List;

/**
 * 现阶段就当是servlet
 */
@Controller

public class UserController {
    
    
    
    @Resource(name = "userServiceImpl")
    IUserService userService;

    public List<User> queryAll(){
    
    
        return userService.queryAll();
    }
}

Additional code:

package com.tianju.controller;

import com.tianju.entity.User;
import com.tianju.service.IUserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Controller;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;
import javax.annotation.Resource;
import java.util.List;


/**
 * 现阶段它就是servlet
 * 注解 :@Controller 扫描时,发现了有这句话就会new对象出来;
 * 代替<bean id="userController" class="com.tianju.controller.UserController">
 *   id:默认不写小字母小写,如果自己指定,则用 @Controller("userController")
 *   单例:默认是单例;如果想设置不是单例,则 @Scope(value = "PROTOTYPE")
 *   初始化方法:@PostConstruct:在构造函数之后运行
 *   销毁方法:@PreDestroy;在容器销毁之前执行
 *     注解:@Autowired,用来代替<property name="userService" ref="userService"></property>
 */
@Controller("userController")
//@Scope(value = "prototype") // 指定不是单例
public class UserController {
    
    
    // 自己new的对象,不在容器中,只有spring管理的才会在容器中;
    // 因此这里不能自己new,要交给spring
//    @Autowired // TODO:方案3,用一个注解@Resource(name = "userServiceImpl1") 代替 @Autowired 和 @Qualifier("userServiceImpl1")
    // TODO:如果有两个实现类,怎么解决:方案一:指定一下名字
    /**
     * 注入的时候:1.按照类型注入,寻找IUserService的实现类注入进来;
     *          2.方案1:如果有多个实现类,则按照变量名字的id在容器中找对应的实现类;或者按照3解决
     *          3.方案2:意外情况:如果变量名不想改,怎么搞? 可以配合  @Qualifier("userServiceImp1") 进行指定;
     *          4.方案3:用一个注解@Resource(name = "userServiceImpl1"),既可以注入,也可以指定
     *            代替@Autowired 和 @Qualifier("userServiceImpl1");
     *         补充:@Autowired 是spring开发的; @Resource是java的
     */
//    @Qualifier("userServiceImpl1") // TODO:方案2,用注解 @Qualifier("userServiceImp1") 进行指定
    @Resource(name = "userServiceImpl1") // TODO:方案3,用一个注解@Resource(name = "userServiceImpl1") 代替 @Autowired 和 @Qualifier("userServiceImpl1")

    private IUserService userService;
//    private IUserService userServiceImpl; // TODO:方案1.指定名字

//    public void setUserService(IUserService userService) {
    
    
//        this.userService = userService;
//    }

    @PostConstruct // 在构造函数之后运行
    public void init(){
    
    
        System.out.println("控制器 Controller init");
    }
    @PreDestroy // 在容器销毁之前执行
    public void destroy(){
    
    
        System.out.println("Controller destroy");
    }

    public List<User> queryAll(){
    
    
        return userService.queryAll();
//        return userServiceImpl.queryAll(); // TODO:方案1.指定名字
    }

}

Spring enhancement method - to enhance a batch of classes

insert image description here

insert image description here
insert image description here

Enhanced with configuration files

insert image description here

1. Enhanced class LogActiveDemo.java file

package com.tianju.aop;

import org.springframework.stereotype.Component;

/**
 * 增强类---用来给别的类做增强
 * 1.需要在容器中
 */
@Component
public class LogActiveDemo {
    
    
    public void before(){
    
    
        System.out.println("增强类的before==========");
    }
    public void after(){
    
    
        System.out.println("增强类的 after==========");
    }
    public void afterReturning(){
    
    
        System.out.println("增强类的 beforeReturning==========");
    }
    public void afterThrowing(){
    
    
        System.out.println("增强类的 beforeThrowing==========");
    }
}

2. Enhanced class UserController.java file

package com.tianju.controller;

import org.springframework.stereotype.Controller;

/**
 * 被增强的类---被增强类增强
 * 1.需要在容器中;
 */
@Controller
public class UserController {
    
    
    public void add(){
    
    
        System.out.println("add a new user");
    }
}

3. Enhanced and enhanced configuration

aop:config+
aop:aspect+
pointcut=“execution(* com.tianju.controller.UserController.*(…))”

insert image description hereIf all methods of all classes are enhanced:

pointcut=“execution( * com.tianju.controller. * .*(…))”

beans.xml file

<?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:aop="http://www.springframework.org/schema/aop"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd
        http://www.springframework.org/schema/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

<!--    进行扫描,保证增强类和被增强的类都在容器中-->
    <context:component-scan base-package="com.tianju"></context:component-scan>

<!--    进行增强方法的配置-->
    <aop:config>
<!--        增强类是容器中的 logActiveDemo -->
        <aop:aspect id="logActiveDemo" ref="logActiveDemo">
<!--           pointcut="execution(* com.tianju.controller.UserController.*(..))" 作用在所有方法上-->
            <aop:before method="before" pointcut="execution(* com.tianju.controller.UserController.*(..))"></aop:before>
            <aop:after method="after" pointcut="execution(* com.tianju.controller.UserController.*(..))"></aop:after>
            <aop:after-returning method="afterReturning" pointcut="execution(* com.tianju.controller.UserController.*(..))"></aop:after-returning>
            <aop:after-throwing method="afterThrowing" pointcut="execution(* com.tianju.controller.UserController.*(..))"></aop:after-throwing>
        </aop:aspect>

    </aop:config>

</beans>

4. Test cases and their results ClassPathXmlApplicationContext("beans.xml");

package com.tianju.test;

import com.tianju.controller.UserController;

import org.springframework.context.support.ClassPathXmlApplicationContext;

public class LogDemoTest1 {
    
    
    public static void main(String[] args) {
    
    
        ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
        UserController userController = ac.getBean(UserController.class);
        userController.add();
    }
}

insert image description here

Enhanced with annotations

insert image description here

1. Enhanced class LogActiveDemo.java file @Aspect, (@Before(“execution(* com.tianju.controller.UserController.*(…))”), @After, @AfterReturning, @AfterThrowing)

Enhancement class - used to enhance other classes

  • 1. Need @Component in the container;
  • 2. Identify yourself as an enhanced class @Aspect;
  • 3. When does your own method act on @Before, @After, @AfterReturning, @AfterThrowing;
  • 4. Identify which methods you want to enhance, and use custom annotations
package com.tianju.aop;

import org.aspectj.lang.annotation.*;
import org.springframework.stereotype.Component;

/**
 * 增强类---用来给别的类做增强
 * 1.需要在容器中 @Component;
 * 2.标识自己是增强类 @Aspect;
 * 3.要给哪些类做增强 用自定义注解实现
 */
@Component
@Aspect
public class LogActiveDemo {
    
    
    @Before("execution(* com.tianju.controller.UserController.*(..))")
    public void before(){
    
    
        System.out.println("增强类的before==========");
    }
    @After("execution(* com.tianju.controller.UserController.*(..))")
    public void after(){
    
    
        System.out.println("增强类的 after==========");
    }
    @AfterReturning("execution(* com.tianju.controller.UserController.*(..))")
    public void afterReturning(){
    
    
        System.out.println("增强类的 beforeReturning==========");
    }
    @AfterThrowing("execution(* com.tianju.controller.UserController.*(..))")
    public void afterThrowing(){
    
    
        System.out.println("增强类的 beforeThrowing==========");
    }
}

2. Custom annotation MyAnnoClass.java file @Target({ElementType.TYPE}) +@Retention(RetentionPolicy.RUNTIME)

package com.tianju.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 自定义注解,进行是否增强类的选择
 */
@Target({
    
    ElementType.TYPE}) // 这个注解作用在类上
@Retention(RetentionPolicy.RUNTIME) // 在运行时阶段增强
public @interface MyAnnoClass {
    
    
}

3. Enhanced class UserController.java file @MyAnnoClass

Enhanced class—enhanced by the enhanced class

  • 1. @Controller needs to be in the container;
  • 2. To identify yourself as this class is enhanced, use the custom annotation @MyAnnoClass
package com.tianju.controller;

import com.tianju.anno.MyAnnoClass;
import org.springframework.stereotype.Controller;

/**
 * 被增强的类---被增强类增强
 * 1.需要在容器中 @Controller;
 * 2.标识自己这个类被增强,用自定义注解 @MyAnnoClass
 */
@Controller
@MyAnnoClass
public class UserController {
    
    
    public void add(){
    
    
        System.out.println("add a new user");
    }
}

4. The configuration file SpringConfig.java file opens the dynamic proxy @EnableAspectJAutoProxy

package com.tianju.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan("com.tianju")
@EnableAspectJAutoProxy // 让动态代理生效
public class SpringConfig {
    
    
}

5. Test case AnnotationConfigApplicationContext(SpringConfig.class);

package com.tianju.test;

import com.tianju.config.SpringConfig;
import com.tianju.controller.UserController;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class LogConfigDemoTest1 {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserController userController = ac.getBean(UserController.class);
        userController.add();
    }
}

Simplification: From @Before("execution(* com.tianju.controller.UserController.*(…))") to @After("@annotation(com.tianju.anno.MyAnnoMethod)")

insert image description here

1. Custom annotation MyAnnoMethod.java file @Target({ElementType.METHOD})

package com.tianju.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 标识哪些方法要做加强,替换
 * @Before("execution(* com.tianju.controller.UserController.*(..))")
 */

@Target({
    
    ElementType.METHOD}) // 这个注释作用在方法上
@Retention(RetentionPolicy.RUNTIME) // 以后全部用这个,运行时阶段
public @interface MyAnnoMethod {
    
    
}

2. Enhanced class LoginActiveAnnoMethod.java file @Before("@annotation(com.tianju.anno.MyAnnoMethod)")

Enhanced class—enhances methods of other classes

  • 1. In a container;
  • 2. It is an enhanced class;
  • 3. Which methods can be enhanced by labeling
package com.tianju.aop;

import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;


/**
 * 增强类---给别的类的方法做增强
 * 1.在容器中;
 * 2.是增强类;
 * 3.标注可以给哪些方法做增强
 */
@Component
@Aspect
public class LoginActiveAnnoMethod {
    
    
    @Before("@annotation(com.tianju.anno.MyAnnoMethod)")
    public void before(){
    
    
        System.out.println("~~~~~~~~~~~~~~~利用标注了某个注解的 方法 进行增强~ 增强方法的 before 方法~~~~~~~~~~");
    }
}

3. Enhanced class OpusController.java file @MyAnnoMethod

package com.tianju.controller;

import com.tianju.anno.MyAnnoMethod;
import org.springframework.stereotype.Controller;

@Controller
public class OpusController {
    
    
    @MyAnnoMethod // 会被增强
    public void add(){
    
    
        System.out.println("标注 @MyAnnoMethod 注解 被增强类的某个方法增强");
    }

    // 没有标注@MyAnnoMethod,不会被增强
    public void insert(){
    
    
        System.out.println("没有标注 @MyAnnoMethod 注解");
    }
}

4. The configuration file SpringConfig.java file opens the dynamic proxy @EnableAspectJAutoProxy

package com.tianju.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan("com.tianju")
@EnableAspectJAutoProxy // 让动态代理生效
public class SpringConfig {
    
    
}

5.测试AnnotationConfigApplicationContext(SpringConfig.class)

package com.tianju.test;

import com.tianju.config.SpringConfig;
import com.tianju.controller.OpusController;
import com.tianju.controller.UserController;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class LogMyAnnoMethodTest {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
        OpusController opusController = ac.getBean(OpusController.class);
        opusController.add();
        System.out.println("________________________");
        opusController.insert();
    }
}

insert image description here

Another way: @Before("@within(org.springframework.stereotype.Controller)") + log case

1. Define an enhanced method, marked @within

LogActiveWith.java文件;@Before(“@within(org.springframework.stereotype.Controller)”)

When enhancing other classes, you can use JoinPoint to

  • 1. Can know what class is accessed;
  • 2. Can know what the target method of access is;
  • 3. Can know what the parameters of the access are;
package com.tianju.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;

import java.util.Arrays;
import java.util.Date;

/**
 * 增强类--给别的方法做增强
 * 1.在容器中;
 * 2.是增强类;
 * 3.给哪些方法做增强;
 */

@Component // 在容器中
@Aspect // 是增强类
public class LogActiveWith {
    
    
    /**
     * 增强别的类时,通过JoinPoint能够
     * 1.能知道访问的类是啥;
     * 2.能知道访问的目标方法是啥;
     * 3.能知道访问传的参数是啥;
     * @param joinPoint
     */
    @Before("@within(org.springframework.stereotype.Controller)")
    public void before(JoinPoint joinPoint){
    
    
        // 1.获取被增强的方法名
        String className = joinPoint.getTarget().getClass().getName();
        // 2.获取访问的目标方法是啥
        String methodName = joinPoint.getSignature().getName();
        // 3.能知道访问时传的参数是啥
        Object[] args = joinPoint.getArgs();
        System.out.println(
                "在"+new Date()
                + "时,访问了" + className
                + "类的," + methodName
                + "方法,传的参数为 "+ Arrays.toString(args));
    }
}

2. Write the logic of the controller normally

MoneyController.java file

package com.tianju.controller;

import org.springframework.stereotype.Controller;

/**
 * 被增强的类,
 * 1.在容器中;2.被增强;
 * 记录交易的日志数据
 */
@Controller
public class MoneyController {
    
    
    public void pay(Double money){
    
    
        System.out.println("~~~~~~~进行支付~~~~~~");
    }

    public void income(Double income){
    
    
        System.out.println("~~~~~~~~~~收入~~~~~~~~~");
    }
}

3. Configuration file + test

Configuration file SpringConfig.java file, @EnableAspectJAutoProxy

package com.tianju.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan("com.tianju")
@EnableAspectJAutoProxy // 让动态代理生效
public class SpringConfig {
    
    
}

test case

package com.tianju.test;

import com.tianju.config.SpringConfig;
import com.tianju.controller.MoneyController;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class MoneyDemoTest {
    
    
    public static void main(String[] args) {
    
    
        AnnotationConfigApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
        MoneyController moneyController = ac.getBean(MoneyController.class);
        moneyController.pay(500.58);
        moneyController.income(458.69);
    }
}

Printed log information

insert image description here

The upgraded method @Around can implement @Before, @After, @AfterReturning, @AfterThrowing

around method, around method

  • Can replace before, after, afterReturning, afterThrowing
  • 1. In the container; 2. It is the enhancement method; 3. For whom to enhance
package com.tianju.aop;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;

/**
 * around方法,环绕方法
 * 可以替代之前的before,after,afterReturning,afterThrowing
 * 1.在容器中;2.是增强方法;3.给谁做增强
 */
@Component
@Aspect
public class LogActiveAround {
    
    

    @Around("@within(org.springframework.stereotype.Controller)")
    public void around(ProceedingJoinPoint joinPoint){
    
    
        String className = joinPoint.getTarget().getClass().getName();// 获取被增强的类名
        String methodName = joinPoint.getSignature().getName();// 获取被增强类的方法名
        Object[] args = joinPoint.getArgs();//获取增强方法的参数
        // 1.@before 在方法执行前做一些事情;
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd hh:mm:ss");
        String beforeAspectLog = "【执行前】在" + sdf.format(new Date())+"时,开始执行"+className+"类的"+methodName+"方法,传的参数是"+ Arrays.toString(args);
        System.out.println(beforeAspectLog);
        try {
    
    
            // 此时方法执行也由joinPoint控制
            joinPoint.proceed(args); // 执行目标方法
            // 2.在方法正常执行完成后做一些事情;
            System.out.println("正常执行完成");
        } catch (Throwable e) {
    
    
            // 3.@AfterThrowing 在抛出异常后执行代码
            String afterThrowingLog = "【异常】在" + sdf.format(new Date())+"时,执行"+className+"类的"+methodName+"方法,传的参数是"+ Arrays.toString(args) +"出现异常";
            System.out.println(afterThrowingLog);
        } finally {
    
    
            // 4.@AfterReturning 在返回后执行代码
            String afterReturningLog = "【完成】在" + sdf.format(new Date())+"时,完成了"+className+"类的"+methodName+"方法,传的参数是"+ Arrays.toString(args);
            System.out.println(afterReturningLog);
        }
    }
}

Summarize

Spring can create new objects, assign values ​​to object properties, and enhance methods;
remember the common annotations of spring;

insert image description here

insert image description here

Guess you like

Origin blog.csdn.net/Pireley/article/details/131295533