学习Spring的01

99 阅读6分钟

什么是控制反转

控制反转:IoC(Inversion of Control)
反转是什么?
反转是两件事:
第一:不在程序中采用硬编码的方式来new对象了。new对象的权利交出去了
第二:不在程序中采用硬编码的方式维护对象的关系了。对象之间关系的维护权,也不管了,交出去了。
控制反转:是一种编程思想

Spring框架

Spring 框架实现了控制反转 IoC 这种思想
Spring 框架可以帮助 new 对象
Spring 框架可以帮助维护对象和对象之间的关系
Spring 是一个实现了 IoC 思想的容器
控制反转的实现方式有多种,比较重要的叫做:依赖注入(Dependency Injection)
依赖注入,包括两种常见的方式:
1、set注入(执行set方法给属性赋值)
2、构造方法注入 (执行构造方法给属性赋值)

Spring的8大模块

Spring core 控制反转
Spring AOP 面向切面编程
Spring Web MVC
Spring DAO 提供了单独支持JDBC操作的API
Spring Webflux
Spring ORM 支持集成常见的ORM框架
Spring Web
Spring Context

第一个Spring程序

写一个User类

Pasted image 20240816160124.png 设置Spring配置文件 Pasted image 20240816160213.png 创建测试类


import org.junit.Test;  
import org.springframework.context.ApplicationContext;  
import org.springframework.context.support.ClassPathXmlApplicationContext;  
  
public class FirstSpringTest {  
    @Test  
    public void testFirstSpringCode() {  
        // 1.获取容器对象  
        // 应用上下文,Spring容器,ApplicationContext是个接口  
        // ClassPathXmlApplicationContext专门从类路径加载Spring配置文件的Spring上下文对象  
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");  
        // 2.从容器中根据ID获取对象  
        Object userBean = applicationContext.getBean("userBean");  
        System.out.println(userBean);  
    }  
}

打印结果 Pasted image 20240816160309.png 默认情况下Spring会通过反射机制,调用无参数构造方法来实例化对象
测试一下 Pasted image 20240821143121.png bean可以配置非自定义类
测试效果 Pasted image 20240821144447.png Object类型无法调用,该类型的方法,使用以下代码可以使用指定类型接收,且不需要强制类型转换

public class FirstSpringTest {  
    @Test  
    public void testFirstSpringCode() {  
        // 1.获取容器对象  
        // 应用上下文,Spring容器,ApplicationContext是个接口  
        // ClassPathXmlApplicationContext专门从类路径加载Spring配置文件的Spring上下文对象  
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring.xml");  
        // 2.从容器中根据ID获取对象  
        Object userBean = applicationContext.getBean("userBean");  
        System.out.println(userBean);  
  
        Date dateBean = applicationContext.getBean("dateBean", Date.class);  
        System.out.println(dateBean);  
    }  
}

ApplicationContext的超级父接口是,BeanFactory,Bean工厂就是生产Bean对象的一个工厂对象 BeanFactory是IoC容器的顶级接口
Spring底层的IoC机制是:XML解析 + 工厂模式 + 反射机制

Log4j2日志框架

启用Log4j2:
1、配置依赖

<dependency>  
    <groupId>org.apache.logging.log4j</groupId>  
    <artifactId>log4j-core</artifactId>  
    <version>2.23.1</version>  
</dependency>  
<dependency>  
    <groupId>org.apache.logging.log4j</groupId>  
    <artifactId>log4j-slf4j2-impl</artifactId>  
    <version>2.23.1</version>  
</dependency>

2、编写配置文件

<?xml version="1.0" encoding="utf-8" ?>
<configuration>
    <loggers>
        <!--
        level指定日志级别,从低到高的顺序是
        ALL < TRACE < DEBUG < INFO < ERROR < FATAL < OFF
    -->
        <root level="DEBUG">
            <appender-ref ref="spring6log"/>
        </root>
    </loggers>
    <appenders>
        <!--  输出信息到控制台  -->
        <console name="spring6log" target="SYSTEM_OUT">
            <!--   控制日志输出格式   -->
            <PatternLayout pattern="%d{yyyy-MM-dd HH:mm:ss SSS} [%t] %-3level %logger{1024} - %msg%n"/>
        </console>
    </appenders>

</configuration>

打印结果如下 Pasted image 20240821153556.png 自己如何使用Log4j2


//1、创建日志记录对象  
//获取FirstSpringTest类的日志记录对象  
Logger logger = LoggerFactory.getLogger(FirstSpringTest.class);  
//2、记录日志  
logger.debug("这是一条调试信息");

打印效果 Pasted image 20240822134327.png

Spring对IoC的实现

依赖注入实现IoC

set注入


public class UserDao {  
    private static final Logger logger = LoggerFactory.getLogger(UserDao.class);  
    public void insert() {  
        logger.info("数据库正在保存用户信息");  
    }  
}

public class UserService {  
    private UserDao userDao;  
    //必须要提供一个set方法  
    //Spring容器会调用这个set方法,来给userDao属性赋值  
    public void setUserDao(UserDao userDao) {  
        this.userDao = userDao;  
    }  
  
    public void saveUser() {  
        //保存用户信息到数据库  
        userDao.insert();  
    }  
}

<?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">
    <!--配置dao-->
    <bean id="userDao" class="com.spring6.dao.UserDao"/>
    <!--配置Service-->
    <bean id="userService" class="com.spring6.service.UserService">
    <!--调用对应的set方法需要配置Property标签-->
    <!--ref是引用,ref是指定要注入的Bean的ID-->
        <property name="userDao" ref="userDao">

        </property>
    </bean>
</beans>

public class DITest {  
    @Test  
    public void testDI() {  
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springDi.xml");  
        UserService userService = applicationContext.getBean("userService", UserService.class);  
        userService.saveUser();  
    }  
}

Pasted image 20240822144324.png 通过set方法注入使Service不再有dao对象

set注入内部Bean和外部Bean

public class OrderDao {  
  
    private static final Logger logger = LoggerFactory.getLogger(OrderDao.class);  
    public void generate() {  
        logger.info("订单正在生成。。。。。。。");  
    }  
}

public class OrderService {  
  
    private OrderDao orderDao;  
  
    public void setOrderDao(OrderDao orderDao) {  
        this.orderDao = orderDao;  
    }  
  
    public void generate() {  
        orderDao.generate();  
    }  
}

<?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="orderDaoBean" class="com.spring6.dao.OrderDao">
    </bean>
    <!--外部Bean-->
    <bean id="orderServiceBean" class="com.spring6.service.OrderService">
        <property name="orderDao" ref="orderDaoBean">
        </property>
    </bean>
	<!--内部Bean-->
    <bean id="orderServiceBean1" class="com.spring6.service.OrderService">
        <property name="orderDao">
            <bean class="com.spring6.dao.OrderDao"/>
        </property>
    </bean>
</beans>


public class DITest {  
  
    @Test  
    public void testSetDi() {  
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");  
        OrderService orderService = applicationContext.getBean("orderServiceBean", OrderService.class);  
        orderService.generate();  
  
        OrderService orderService1 = applicationContext.getBean("orderServiceBean1", OrderService.class);  
        orderService1.generate();  
    }  
}

打印结果 Pasted image 20240822154503.png

构造方法注入


public class UserDao {  
    private static final Logger logger = LoggerFactory.getLogger(UserDao.class);  
    public void insert() {  
        logger.info("数据库正在保存用户信息");  
    }  
}

public class VipDao {  
    private static final Logger logger = LoggerFactory.getLogger(VipDao.class);  
    public void insert() {  
        logger.info("数据库正在保存尊贵的VIP用户信息");  
    }  
}

public class CustomService {  
    private UserDao userDao;  
    private VipDao vipDao;  
  
    public CustomService(UserDao userDao, VipDao vipDao) {  
        this.userDao = userDao;  
        this.vipDao = vipDao;  
    }  
  
    public void save() {  
        userDao.insert();  
        vipDao.insert();  
    }  
}

<?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="userDaoBean" class="com.spring6.dao.UserDao">
    </bean>
    <bean id="vipDaoBean" class="com.spring6.dao.VipDao">
    </bean>
    <bean id="customServiceBean" class="com.spring6.service.CustomService">
        <!--构造注入-->
        <!--构造构造方法的第一个参数,下标index 0-->
        <constructor-arg index="0" ref="userDaoBean"/>
        <!--构造构造方法的第二个参数,下标index 1-->
        <constructor-arg index="1" ref="vipDaoBean"/>
    </bean>
</beans>

public class DITest {  
    @Test  
    public void testDI() {  
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("springDi.xml");  
        UserService userService = applicationContext.getBean("userService", UserService.class);  
        userService.saveUser();  
        VipService vipService = applicationContext.getBean("vipServiceDao", VipService.class);  
        vipService.saveVipUserInfo();  
  
        ClassPathXmlApplicationContext appContext = new ClassPathXmlApplicationContext("construct.xml");  
        CustomService customService = appContext.getBean("customServiceBean", CustomService.class);  
        customService.save();  
    }  
}
简单类型的set注入
public class User {  
    private String username;  
    private String password;  
  
    public void setUsername(String username) {  
        this.username = username;  
    }  
  
    public void setPassword(String password) {  
        this.password = password;  
    }  
  
    @Override  
    public String toString() {  
        return "User{" +  
                "username='" + username + '\'' +  
                ", password='" + password + '\'' +  
                '}';  
    }  
}

<!--  简单类型的set注入  -->
    <bean id="userBean" class="com.spring6.bean.User">
        <property name="username" value="username"/>
        <property name="password" value="password"/>
    </bean>

public class DITest {  
    @Test  
    public void testEasy() {  
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");  
        User user = applicationContext.getBean("userBean", User.class);  
        System.out.println(user);  
    }  
  
}

打印结果 Pasted image 20240823145047.png

级联属性注入

需要实现get属性

public class User {  
    private String username;  
    private String password;  
  
    public void setUsername(String username) {  
        this.username = username;  
    }  
  
    public void setPassword(String password) {  
        this.password = password;  
    }  
  
  
  
    @Override  
    public String toString() {  
        return "User{" +  
                "username='" + username + '\'' +  
                ", password='" + password + '\'' +  
                '}';  
    }  
}

public class People {  
    private String name;  
    private User user;  
  
    public User getUser() {  
        return user;  
    }  
  
    public void setUser(User user) {  
        this.user = user;  
    }  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    @Override  
    public String toString() {  
        return "People{" +  
                "name='" + name + '\'' +  
                '}';  
    }  
  
  
  
}

注意此处顺序不能写反,先对象,再属性
	<bean id="peopleBean" class="com.spring6.bean.People">
        <property name="user" ref="userBean" />
        <property name="user.username" value="张三" />
    </bean>

    <bean id="userBean" class="com.spring6.bean.User">
    </bean>


public class DITest {  
    @Test  
    public void testEasy() {  
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("set-di.xml");  
        User user = applicationContext.getBean("userBean", User.class);  
        System.out.println(user);  
    }  
  
}

Pasted image 20240823154902.png

数组注入

1、简单类型,和视频学的,这段代码我真一个字都不想改(哈哈哈哈)

public class QianDaYe {  
    private String[] hobbies;  
  
    public void setHobbies(String[] hobbies) {  
        this.hobbies = hobbies;  
    }  
  
    @Override  
    public String toString() {  
        return "QianDaYe{" +  
                "hobbies=" + Arrays.toString(hobbies) +  
                '}';  
    }  
}

<bean id="yuQian" class="com.spring6.bean.QianDaYe">
<!--数组属性当中的类型是String简单类型-->
    <property name="hobbies">
        <array>
            <value>抽烟</value>
            <value>喝酒</value>
            <value>烫头</value>
        </array>
    </property>
</bean>


public class DITest {  
  
    @Test  
    public void testArray() {  
        ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("array-di.xml");  
        QianDaYe yuQian = applicationContext.getBean("yuQian", QianDaYe.class);  
        System.out.println(yuQian);  
    }  
  
    
}

测试 Pasted image 20240828151840.png 2、复杂类型
array里面嵌套ref,完整配置文件如下


public class Pony {  
    private String name;  
  
    public void setName(String name) {  
        this.name = name;  
    }  
  
    @Override  
    public String toString() {  
        return "Pony{" +  
                "name='" + name + '\'' +  
                '}';  
    }  
}


<?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="pony1" class="com.spring6.bean.Pony">
        <property name="name" value="兔子">
        </property>
    </bean>
    <bean id="pony2" class="com.spring6.bean.Pony">
        <property name="name" value="剑齿虎">
        </property>
    </bean>
    <bean id="pony3" class="com.spring6.bean.Pony">
        <property name="name" value="烧饼">
        </property>
    </bean>
    <bean id="yuQian" class="com.spring6.bean.QianDaYe">
<!--数组属性当中的类型是String简单类型-->
        <property name="hobbies">
            <array>
                <value>抽烟</value>
                <value>喝酒</value>
                <value>烫头</value>
            </array>
        </property>
<!--        复杂类型-->
        <property name="ponys">
            <array>
                <ref bean="pony1"/>
                <ref bean="pony2"/>
                <ref bean="pony3"/>
            </array>
        </property>
    </bean>
</beans>

打印结果 Pasted image 20240828153526.png

集合类型注入
public class Person {  
    // 注入List集合类型  
    private List<String> names;  
    // 注入Set集合类型  
    private Set<String> addresses;  
  
    public void setNames(List<String> names) {  
        this.names = names;  
    }  
  
    public void setAddresses(Set<String> addresses) {  
        this.addresses = addresses;  
    }  
  
    @Override  
    public String toString() {  
        return "Person{" +  
                "names=" + names +  
                ", addresses=" + addresses +  
                '}';  
    }  
}

<bean id="person" class="com.spring6.bean.Person">
    <property name="names">
        <!--有序可重复-->
        <list>
            <value>张三</value>
            <value>李四</value>
            <value>张李十二</value>
            <value>张三</value>
        </list>
    </property>
    <property name="addresses">
        <!--无序不可重复-->
        <set>
            <value>监狱</value>
        </set>
    </property>
</bean>

打印结果 Pasted image 20240828155203.png

Map类型注入
public class Person {  
    // 注入List集合类型  
    private List<String> names;  
    // 注入Set集合类型  
    private Set<String> addresses;  
    // Map 类型  
    private Map<Integer, String> phoneNumbers;  
  
    public void setPhoneNumbers(Map<Integer, String> phoneNumbers) {  
        this.phoneNumbers = phoneNumbers;  
    }  
  
    public void setNames(List<String> names) {  
        this.names = names;  
    }  
  
    public void setAddresses(Set<String> addresses) {  
        this.addresses = addresses;  
    }  
  
    @Override  
    public String toString() {  
        return "Person{" +  
                "names=" + names +  
                ", addresses=" + addresses +  
                ", phoneNumbers=" + phoneNumbers +  
                '}';  
    }  
  
}

<bean id="person" class="com.spring6.bean.Person">
    <property name="phoneNumbers">
        <map>
			<!--复杂类型-->
            <entry key-ref="" value-ref="" />
	        <!--简单类型-->
            <entry key="1" value="110"/>
            <entry key="2" value="120"/>
            <entry key="3" value="114"/>
        </map>
    </property>
    <property name="names">
        <!--有序可重复-->
        <list>
            <value>张三</value>
            <value>李四</value>
            <value>张李十二</value>
            <value>张三</value>
        </list>
    </property>
    <property name="addresses">
        <!--无序不可重复-->
        <set>
            <value>监狱</value>
        </set>
    </property>
</bean>

打印结果 Pasted image 20240828160338.png

p 命名空间注入

public class Phone {  
    private String chipType;  
    private String brand;  
    private String price;  
  
    public void setChipType(String chipType) {  
        this.chipType = chipType;  
    }  
  
    public void setBrand(String brand) {  
        this.brand = brand;  
    }  
  
    public void setPrice(String price) {  
        this.price = price;  
    }  
  
    @Override  
    public String toString() {  
        return "Phone{" +  
                "chipType='" + chipType + '\'' +  
                ", brand='" + brand + '\'' +  
                ", price='" + price + '\'' +  
                '}';  
    }  
}


<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
<!--p命名空间注入  xmlns:p="http://www.springframework.org/schema/p"-->
    <bean id="phoneBean" class="com.spring6.bean.Phone" p:chipType="A22" p:brand="iPhone" p:price="$99999999"/>
</beans>



打印结果

Pasted image 20240829145254.png

注入属性文件

第一步:引入context命名空间
第二步:使用context:property-placeholder location标签进行查找 location默认从根路径下,开始加载信息
第三步:${key}取值


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

<!--  引入外部的properties文件
  第一步:引入context命名空间
  第二步:使用context:property-placeholder location标签进行查找
  Location默认从根路径下,开始加载信息
-->
<context:property-placeholder location="jdbc.properties"/>
    <!--配置数据源-->
    <bean id="ds" class="com.spring6.jdbc.MyDataSource">
	<!--  第三步${key}取值-->
        <property name="driver" value="${driverClass}"></property>
        <property name="url" value="${url}"></property>
        <property name="username" value="${username}"></property>
        <property name="password" value="${password}"></property>
    </bean>
</beans>

public class MyDataSource implements DataSource {  
    private String driver;  
    private String url;  
    private String username;  
    private String password;  
  
  
    public void setDriver(String driver) {  
        this.driver = driver;  
    }  
  
    public void setUrl(String url) {  
        this.url = url;  
    }  
  
    public void setUsername(String username) {  
        this.username = username;  
    }  
  
    public void setPassword(String password) {  
        this.password = password;  
    }  
  
  
    @Override  
    public String toString() {  
        return "MyDataSource{" +  
                "driver='" + driver + '\'' +  
                ", url='" + url + '\'' +  
                ", username='" + username + '\'' +  
                ", password='" + password + '\'' +  
                '}';  
    }  
  
    @Override  
    public Connection getConnection() throws SQLException {  
        return null;  
    }  
  
    @Override  
    public Connection getConnection(String username, String password) throws SQLException {  
        return null;  
    }  
  
    @Override  
    public PrintWriter getLogWriter() throws SQLException {  
        return null;  
    }  
  
    @Override  
    public void setLogWriter(PrintWriter out) throws SQLException {  
  
    }  
  
    @Override  
    public void setLoginTimeout(int seconds) throws SQLException {  
  
    }  
  
    @Override  
    public int getLoginTimeout() throws SQLException {  
        return 0;  
    }  
  
    @Override  
    public Logger getParentLogger() throws SQLFeatureNotSupportedException {  
        return null;  
    }  
  
    @Override  
    public <T> T unwrap(Class<T> iface) throws SQLException {  
        return null;  
    }  
  
    @Override  
    public boolean isWrapperFor(Class<?> iface) throws SQLException {  
        return false;  
    }  
}

打印结果 Pasted image 20240905160229.png