Spring入门

1.Spring概述

什么是框架

源自于建筑学,隶属土木工程,后发展到软件工程领域

软件工程框架:经过验证的,具有一定功能的,半成品软件

框架的作用

1.提高开发效率

2.增强可重用性

3.提供编写规范

4.节约维护成本

5.解耦底层实现原理

Spring是什么

Spring是分层的JavaSE/EE应用full-stack轻量级开源框架

Spring的结构体系

底层是核心容器

        Beans

        Core

        Context

        SpringEL表达式

中间层技术

        AOP

        Aspects

应用层技术

        数据访问与数据集成

        Web集成

        Web实现

基于Test测试

Spring优势

方便解耦,简化开发

方便集成各种优秀框架

方便程序的测试

AOP编程的支持

声明式事务的支持

降低JavaEE API的使用难度

Java源码是经典学习范例

2.IoC概述

1.耦合与内聚

耦合(Coupling):代码书写过程中所使用技术的结合紧密度,用于衡量软件中各个模块之间的互联程度

内聚(Cohesion):代码书写过程中单个模块内部各组成部分间的联系,用于衡量软件中各个功能模块内部的功能联系

程序书写的目标:高内聚,低耦合

就是同一个模块内的各个元素之间要高度紧密,但是各个模块之间的相互依存度却不要那么紧密

2.IoC

IoC(Inversion Of Control)控制反转,Spring反向控制应用程序所需要使用的外部资源

Spring控制的资源全部放置在Spring容器中,该容器称为IoC容器

3.IoC入门案例

模拟三层架构中表现层调用业务层功能

        表现层:UserApp模拟UserServlet(使用main方法模拟)

        业务层:UserService

IoC入门案例步骤

1.导入spring坐标(5.1.9.release)

2.编写业务层与表现层(模拟)接口与实现类

3.建立spring配置文件

4.配置所需资源(Service)为spring控制的资源

5.表现层(App)通过spring获取资源(Service实例)

实现

1.导入坐标,添加依赖

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

2.编写业务层接口与实现类 

package com.service;

public interface UserService {
    public void save();
}
package com.service.impl;

import com.service.UserService;

public class UserServiceImpl implements UserService {
    public void save(){
        System.out.println("user service running");
    }
}

3.编写spring配置文件与配置spring控制的资源

进入官网 spring.io

projects-framework-learn-点击所选版本-Core Technologies-找到一个xml文件并复制开头

resources下配置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">
    <!--1.创建spring控制的资源-->
    <bean id="userService" class="com.service.impl.UserServiceImpl"/>
</beans>

4.编写表现层(App)通过spring获取资源

import com.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserApp {
    public static void main(String[] args) {
        //2.加载配置文件
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //3.获取资源
        UserService userService = (UserService) ctx.getBean("userService");

        userService.save();
    }
}

4.IoC配置(xml格式)

1.bean

1.bean的基本配置

名称:bean

类型:标签

归属:beans标签

作用:定义spring中的资源,受此标签定义的资源将受到spring控制

格式

<beans>
	<bean />
</beans>

基本属性

<bean id="beanId" name="beanName1,beanName2" class="ClassName"></bean>

​ id:bean的名称,通过id值获取bean

​ class:bean的类型

​ name:bean的名称,可以通过name值获取bean,用于多人配合时给bean起别名

bean可以定义多个名称,使用name属性完成,中间使用,分割

2.scope属性

名称:scope

类型:属性

归属:bean标签

作用:定义bean的作用范围

格式

<bean scope="singleton"></bean>

取值:

        singleton:设定创建出的对象保存在spring容器中,是一个单例的对象

        prototype:设定创建出的对象保存在spring容器中,是一个非单例的对象

        request、session、application、 websocket :设定创建出的对象放置在web容器对应的位置

scope用于控制bean创建后的对象是否单例

singleton只创建一次对象是在加载容器时创建

prototype在获取对象时创建对象,获取一次创建一次

一个是先加载好用的时候直接给你,另一个是用的时候再创建

3.bean的生命周期

名称:init-method,destroy-method

类型:属性

归属:bean标签

作用:定义bean对象在初始化或销毁时完成的工作

格式

<bean init-method="init" destroy-method="destroy></bean>

取值:bean对应的类中对应的具体方法名

注意事项:

当scope=“singleton”时,spring容器中有且仅有一个对象,init方法在创建容器时仅执行一次

当scope=“prototype”时,spring容器要创建同一类型的多个对象,init方法在每个对象创建时均执行一次

当scope=“singleton”时,关闭容器会导致bean实例的销毁,调用destroy方法一次

当scope=“prototype”时,对象的销毁由垃圾回收机制gc()控制,destroy方法将不会被执行

4.bean对象创建方式

(1)factory-bean

名称:factory-bean

类型:属性

归属:bean标签

作用:定义bean对象创建方式,使用静态工厂的形式创建bean,兼容早期遗留系统的升级工作

格式

<bean class="FactoryClassName" factory-method="factoryMethodName"></bean>

取值:工厂bean中用于获取对象的静态方法名

注意事项:class属性必须配置成静态工厂的类名

(2)factory-bean,factory-method

名称:factory-bean,factory-method

类型:属性

归属:bean标签

作用:定义bean对象创建方式,使用实例工厂的形式创建bean,兼容早期遗留系统的升级工作

格式

<bean factory-bean="factoryBeanId" factory-method="factoryMethodName"></bean>

取值:工厂bean中用于获取对象的实例方法名

注意事项:

        使用实例工厂创建bean首先需要将实例工厂配置bean,交由spring进行管理

        factory-bean是实例工厂的beanId

2.依赖注入

1.DI

IoC(Inversion Of Control)控制翻转,Spring反向控制应用程序所需要使用的外部资源

DI(Dependency Injection)依赖注入,应用程序运行依赖的资源由Spring为其提供,资源进入应用程序的方式称为注入

IoC与DI的关系

IoC与DI是同一件事站在不同角度看待问题

2.set注入

名称:property

类型:标签

归属:bean标签

作用:使用set方法的形式为bean提供资源

格式

<bean>
	<property />
</bean>

基本属性

<property name="propertyName" value="propertyValue" ref="beanId"/>

​name:对应bean中的属性名,要求该属性必须提供可访问的set方法(严格规范为此名称是set方法对应名称)

​ value:设定非引用类型属性对应的值,不能与ref同时使用

​ ref:设定引用类型属性对应bean的id ,不能与value同时使用

注意:一个bean可以有多个property标签

样例

 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">

    <bean id="userService" class="com.service.impl.UserServiceImpl">
            <!--3.将要注入的引用类型的变量通过property属性进行注入,对应的name是要注入的变量名,使用ref属性声明要注入的bean的id-->
            <property name="userDao" ref="userDao"/>
            <property name="num" value="666"/>
    </bean>
    <!--2.将要注入的资源声明为bean-->
    <bean id="userDao" class="com.dao.impl.UserDaoImpl"/>
</beans>
package com.dao.impl;

import com.dao.UserDao;

public class UserDaoImpl implements UserDao {
    public void save(){
        System.out.println("user dao running...");
    }
}

 接口

package com.dao;

public interface UserDao {
    public void save();
}
package com.service.impl;

import com.service.UserService;
import com.dao.UserDao;

public class UserServiceImpl implements UserService {
   //声明一个私有变量
    //注入非引用类型
    private int num;

    public void setNum(int num) {
        this.num = num;
    }

    //注入引用类型
    private UserDao userDao;

    //对需要进行注入的变量添加set方法
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public void save(){
        System.out.println("user service running..."+num);
        userDao.save();
    }
}
import com.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserApp {
    public static void main(String[] args) {
        //2.加载配置文件
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //3.获取资源
        UserService userService = (UserService) ctx.getBean("userService");

        userService.save();
    }
}

3.构造器注入

名称:constructor-arg

类型:标签

归属:bean标签

作用:使用构造方法的形式为bean提供资源,兼容早期遗留系统的升级工作

格式

<bean>
	<constructor-arg />
</bean>

基本属性

<constructor-arg name="argsName" value="argsValue />

name:对应bean中的构造方法所携带的参数名

​value:设定非引用类型构造方法参数对应的值,不能与ref同时使用

其他属性

<constructor-arg index="arg-index" type="arg-type" ref="beanId"/>

ref:设定引用类型构造方法参数对应bean的id ,不能与value同时使用

type :设定构造方法参数的类型,用于按类型匹配参数或进行类型校验

index :设定构造方法参数的位置,用于按位置匹配参数,参数index值从0开始计数

package com.service.impl;

import com.dao.UserDao;
import com.service.UserService;

import javax.jws.soap.SOAPBinding;

public class UserServiceImpl implements UserService {
    private UserDao userDao;
    private int num;
    private  String version;

    public UserServiceImpl(UserDao userDao , int num ,String version){
        this.userDao = userDao;
        this.num =num;
        this.version = version;
    }
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    public void setNum(int num) {
        this.num = num;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public void save(){
        System.out.println("user service running..."+num+" "+version);
        userDao.save();
    }
}
<?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">
<!--
    <bean id="userService" class="com.service.impl.UserServiceImpl">
            <property name="userDao" ref="userDao"/>
            <property name="num" value="666"/>
    </bean>-->
    <bean id="userDao" class="com.dao.impl.UserDaoImpl"/>

    <bean id="userService" class="com.service.impl.UserServiceImpl">
        <!--使用构造方法进行set注入,需要保障注入的属性与bean中定义的属性一致-->
        <!--一致指顺序一致类型一致或使用index解决该问题-->
        <constructor-arg name="userDao" ref="userDao"/>
        <constructor-arg name="num" value="666666"/>
        <constructor-arg name="version" value="ljb"/>
    </bean>
</beans>

4.集合类型数据注入 

名称:array,list,set,map,props

类型:标签

归属:property标签 或 constructor-arg标签

作用:注入集合数据类型属性

格式

<property>
	<list></list>
</property>

list

<property name="mylist">
<list>
    <value>ljb</value>
    <value>66666</value>
    <ref bean="userService"/>
    <bean class="com.service.ApplyService"/>
</list>
</property>

props

<property name="properties">
    <props>
        <prop key="username">root</prop>
        <prop key="password">root</prop>
    </props>
</property>

array

//与list互通
<property name="arr">
    <array>
        <value>ljb</value>
        <value>66666</value>
        <ref bean="userService"/>
        <bean class="com.service.ApplyService"/>
    </array>
</property>

set

<property name="arr">
    <set>
        <value>ljb</value>
        <value>66666</value>
        <ref bean="userService"/>
        <bean class="com.service.ApplyService"/>
    </set>
</property>

map

<property name="hm">
    <map>
        <entry key="name" value="ljb"/>
        <entry key="value" value="666666"/>
        <entry key="userService">
            <ref bean="userService"></ref>
        </entry>
        <entry key="applyService">
            <bean class="applyService"/>
        </entry>
    </map>
</property>

样例

package com.dao;

public interface UserDao {
    public void save();
}
package com.dao;

public interface BookDao {
    public void save();
}
package com.dao.impl;

import com.dao.UserDao;

public class UserDaoImpl implements UserDao {
    private String username;
    private String pwd;
    private String driver;
    public UserDaoImpl(String username, String pwd, String driver) {
        this.username = username;
        this.pwd = pwd;
        this.driver = driver;
    }
    public void save(){
        System.out.println("user dao running...");
    }
}
package com.dao.impl;

import com.dao.BookDao;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.HashSet;
import java.util.Properties;

public class BookDaoImpl implements BookDao {
    private ArrayList al;
    private Properties properties;
    private int[] arr;
    private HashSet hs;
    private HashMap hm;

    public void setAl(ArrayList al) {
        this.al = al;
    }

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    public void setArr(int[] arr) {
        this.arr = arr;
    }

    public void setHs(HashSet hs) {
        this.hs = hs;
    }

    public void setHm(HashMap hm) {
        this.hm = hm;
    }
    @Override
    public void save(){
        System.out.println("book dao running...");
        System.out.println("ArrayList"+al);
        System.out.println("Properties");
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
        System.out.println("HashSet:"+hs);
        System.out.println("HashMap:"+hm);
    }
}
package com.service;

public interface UserService {
    public void save();
}
package com.service.impl;

import com.dao.BookDao;
import com.dao.UserDao;
import com.service.UserService;

public class UserServiceImpl implements UserService {
    private UserDao userDao;
    private int num;
    private String version;
    private BookDao bookDao;
/*
    public UserServiceImpl(UserDao userDao, int num, String version) {
        this.userDao = userDao;
        this.num = num;
        this.version = version;
    }
*/
    public UserServiceImpl() {

    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void setNum(int num) {
        this.num = num;
    }

    public void setVersion(String version) {
        this.version = version;
    }

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
    public void save(){
        System.out.println("user service running..."+num+" "+version);
        userDao.save();
        bookDao.save();
    }
}
<?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:util="http://www.springframework.org/schema/util"
       xmlns:set="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!--
    <bean id="userService" class="com.service.impl.UserServiceImpl">
            <property name="userDao" ref="userDao"/>
            <property name="num" value="666"/>
    </bean>-->
<!--    <bean id="userDao" class="com.dao.impl.UserDaoImpl"/>

    <bean id="userService" class="com.service.impl.UserServiceImpl">-->
        <!--使用构造方法进行set注入,需要保障注入的属性与bean中定义的属性一致-->
        <!--一致指顺序一致类型一致或使用index解决该问题-->
       <!-- <constructor-arg name="userDao" ref="userDao"/>
        <constructor-arg name="num" value="666666"/>
        <constructor-arg name="version" value="ljb"/>
    </bean>-->
    <bean id="userDao" class="com.dao.impl.UserDaoImpl">
        <constructor-arg index="2" value="123"/>
        <constructor-arg index="1" value="root"/>
        <constructor-arg index="0" value="com.mysql.jdbc.Driver"/>
    </bean>

    <bean id="userService" class="com.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
        <property name="bookDao" ref="bookDao"/>
    </bean>
    <bean id="bookDao" class="com.dao.impl.BookDaoImpl">
    <property name="al">
        <util:list list-class="java.util.ArrayList">
            <value>ljb</value>
            <value>66666</value>
        </util:list>
    </property>
    <property name="properties">
        <props>
            <prop key="name">ljb666</prop>
            <prop key="value">666666</prop>
        </props>
    </property>
    <property name="arr">
        <array>
        <value>123456</value>
        <value>66666</value>
        </array>
    </property>
    <property name="hs">
        <set:set set-class="java.util.HashSet">
            <value>ljb</value>
            <value>66666</value>
        </set:set>
    </property>
    <property name="hm">
        <util:map map-class="java.util.HashMap">
            <entry key="name" value="ljb66666"/>
            <entry key="value" value="666666"/>
        </util:map>
    </property>
    </bean>
</beans>

5.使用p命名空间简化配置

名称:p:propertyName,p:propertyName-ref

类型:属性

归属:bean标签

作用:为bean注入属性值

格式

<bean p:propertyName="propertyValue" p:propertyName-ref="beanId"/>

注意:使用p命令空间需要先开启spring对p命令空间的的支持,在beans标签中添加对应空间支持

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

样例

<?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:util="http://www.springframework.org/schema/util"
       xmlns:set="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!--
    <bean id="userService" class="com.service.impl.UserServiceImpl">
            <property name="userDao" ref="userDao"/>
            <property name="num" value="666"/>
    </bean>-->
<!--    <bean id="userDao" class="com.dao.impl.UserDaoImpl"/>

    <bean id="userService" class="com.service.impl.UserServiceImpl">-->
        <!--使用构造方法进行set注入,需要保障注入的属性与bean中定义的属性一致-->
        <!--一致指顺序一致类型一致或使用index解决该问题-->
       <!-- <constructor-arg name="userDao" ref="userDao"/>
        <constructor-arg name="num" value="666666"/>
        <constructor-arg name="version" value="ljb"/>
    </bean>-->
    <bean id="userDao" class="com.dao.impl.UserDaoImpl">
        <constructor-arg index="2" value="123"/>
        <constructor-arg index="1" value="root"/>
        <constructor-arg index="0" value="com.mysql.jdbc.Driver"/>
    </bean>


    <bean
            id="userService"
            class="com.service.impl.UserServiceImpl"
            p:userDao-ref="userDao"
            p:bookDao-ref="bookDao"
    />

    <bean id="bookDao" class="com.dao.impl.BookDaoImpl">
    <property name="al">
        <util:list list-class="java.util.ArrayList">
            <value>ljb</value>
            <value>66666</value>
        </util:list>
    </property>
    <property name="properties">
        <props>
            <prop key="name">ljb666</prop>
            <prop key="value">666666</prop>
        </props>
    </property>
    <property name="arr">
        <array>
        <value>123456</value>
        <value>66666</value>
        </array>
    </property>
    <property name="hs">
        <set:set set-class="java.util.HashSet">
            <value>ljb</value>
            <value>66666</value>
        </set:set>
    </property>
    <property name="hm">
        <util:map map-class="java.util.HashMap">
            <entry key="name" value="ljb66666"/>
            <entry key="value" value="666666"/>
        </util:map>
    </property>
    </bean>
</beans>

6.SpEL

Spring提供了对EL表达式的支持,统一属性注入格式

类型:属性值

归属:value属性值

作用:为bean注入属性值

格式

<property value="EL"></bean>

 注意:所有属性值不区分是否引用类型,统一使用value赋值

常量: #{10} #{3.14} #{2e5} #{‘test’}

引用bean:#{beanId}

引用bean属性: #{beanId.propertyName}

引用bean方法: beanId.methodName().method2()

引用静态方法: T(java.lang.Math).PI

运算符支持: #{3 lt 4 == 4 ge 3}

正则表达式支持: #{user.name matches‘[a-z]{6,}’}

集合支持: #{likes[3]}

样例

<?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:util="http://www.springframework.org/schema/util"
       xmlns:set="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
		https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!--
    <bean id="userService" class="com.service.impl.UserServiceImpl">
            <property name="userDao" ref="userDao"/>
            <property name="num" value="666"/>
    </bean>-->
<!--    <bean id="userDao" class="com.dao.impl.UserDaoImpl"/>

    <bean id="userService" class="com.service.impl.UserServiceImpl">-->
        <!--使用构造方法进行set注入,需要保障注入的属性与bean中定义的属性一致-->
        <!--一致指顺序一致类型一致或使用index解决该问题-->
       <!-- <constructor-arg name="userDao" ref="userDao"/>
        <constructor-arg name="num" value="666666"/>
        <constructor-arg name="version" value="ljb"/>
    </bean>-->
    <bean id="userDao" class="com.dao.impl.UserDaoImpl">
        <constructor-arg index="2" value="123"/>
        <constructor-arg index="1" value="root"/>
        <constructor-arg index="0" value="com.mysql.jdbc.Driver"/>
    </bean>

   <!-- <bean
            id="userService"
            class="com.service.impl.UserServiceImpl"
            p:userDao-ref="userDao"
            p:bookDao-ref="bookDao"
    />-->
    <bean id="userService" class="com.service.impl.UserServiceImpl">
        <property name="userDao" value="#{userDao}"/>
        <property name="bookDao" value="#{bookDao}"/>
        <property name="num" value="#{666666}"/>
        <property name="version" value="#{'ljb'}"/>
    </bean>

    <bean id="bookDao" class="com.dao.impl.BookDaoImpl">
    <property name="al">
        <util:list list-class="java.util.ArrayList">
            <value>ljb</value>
            <value>66666</value>
        </util:list>
    </property>
    <property name="properties">
        <props>
            <prop key="name">ljb666</prop>
            <prop key="value">666666</prop>
        </props>
    </property>
    <property name="arr">
        <array>
        <value>123456</value>
        <value>66666</value>
        </array>
    </property>
    <property name="hs">
        <set:set set-class="java.util.HashSet">
            <value>ljb</value>
            <value>66666</value>
        </set:set>
    </property>
    <property name="hm">
        <util:map map-class="java.util.HashMap">
            <entry key="name" value="ljb66666"/>
            <entry key="value" value="666666"/>
        </util:map>
    </property>
    </bean>
</beans>

3.分块简化

1.properties文件

Spring提供了读取外部properties文件的机制,使用读取到的数据为bean的属性赋值

操作步骤

1.准备外部properties文件

2.开启context命名空间支持

xmlns:context="http://www.springframework.org/schema/context"

3.加载指定的properties文件

<context:property-placeholder location="classpath:filename.properties">

4.使用加载的数据

<property name="propertyName" value="${propertiesName}"/>

注意:如果需要加载所有的properties文件,可以使用*.properties表示加载所有的properties文件

注意:读取数据使用**${propertiesName}格式进行,其中propertiesName**指properties文件中的属性名

<?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:util="http://www.springframework.org/schema/util"
       xmlns:set="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       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">
    <!--1.加载命名空间的支持-->
    <!--xmlns:context="http://www.springframework.org/schema/context"-->
    <!--2.加载配置文件-->
    <context:property-placeholder location="classpath:*.properties"/>
    <bean id="userDao" class="com.dao.impl.UserDaoImpl">
        <!--3.使用加载的数据-->
        <property name="userName" value="${username}"/>
        <property name="password" value="${pwd}"/>
    </bean>
    <bean id="bookDao" class="com.dao.impl.BookDaoImpl"/>

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

</beans>

在resources下创建data.properties

username=root
pwd=123
package com.dao.impl;

import com.dao.UserDao;

public class UserDaoImpl implements UserDao {
    private String userName;
    private String password;

    public void setUserName(String userName) {
        this.userName = userName;
    }

    public void setPassword(String password) {
        this.password = password;
    }

    public void save(){
        System.out.println("user dao running..."+userName+" "+password);
    }
}
package com.dao.impl;

import com.dao.BookDao;

public class BookDaoImpl implements BookDao {
    public void save(){
        System.out.println("book dao running...");
    }
}
package com.service.impl;

import com.dao.BookDao;
import com.dao.UserDao;
import com.service.UserService;


public class UserServiceImpl implements UserService {
    private UserDao userDao;
    private BookDao bookDao;

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }
    public void save(){
        System.out.println("user service running...");
        userDao.save();
        bookDao.save();
    }
}

2.团队开发

名称:import

类型:标签

归属:beans标签

作用:在当前配置文件中导入其他配置文件中的项

格式

<beans>
    <import />
</beans>

基本属性:

<import resource=“config.xml"/>

         resource:加载的配置文件名 

Spring容器加载多个配置文件

new ClassPathXmlApplicationContext("config1.xml","config2.xml");

Spring容器中的bean定义冲突问题

同id的bean,后定义的覆盖先定义的

导入配置文件可以理解为将导入的配置文件复制粘贴到对应位置

导入配置文件的顺序与位置不同可能会导致最终程序运行结果不同

样例

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" xmlns:util="http://www.springframework.org/schema/util"
       xmlns:set="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       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">
    <!--1.加载命名空间的支持-->
    <!--xmlns:context="http://www.springframework.org/schema/context"-->
    <!--2.加载配置文件-->
    <context:property-placeholder location="classpath:*.properties"/>

    <!--<bean id="userDao" class="com.dao.impl.UserDaoImpl">
        &lt;!&ndash;3.使用加载的数据&ndash;&gt;
        <property name="userName" value="${username}"/>
        <property name="password" value="${pwd}"/>
    </bean>
    <bean id="bookDao" class="com.dao.impl.BookDaoImpl"/>

    <bean id="userService" class="com.service.impl.UserServiceImpl">
        <property name="userDao" ref="userDao"/>
        <property name="bookDao" ref="bookDao"/>
    </bean>-->
    <import resource="applicationContext-user.xml"/>
    <import resource="applicationContext-book.xml"/>

</beans>

 applicationContext-user.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" xmlns:util="http://www.springframework.org/schema/util"
       xmlns:set="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       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">

    <bean id="userDao" class="com.dao.impl.UserDaoImpl">
        <!--3.使用加载的数据-->
        <property name="userName" value="${username}"/>
        <property name="password" value="${pwd}"/>
    </bean>


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

</beans>

applicationContext-user.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" xmlns:util="http://www.springframework.org/schema/util"
       xmlns:set="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       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">

    <bean id="bookDao" class="com.dao.impl.BookDaoImpl"/>

</beans>

3.ApplicationContext

1.ApplicationContext是一个接口,提供了访问spring容器的API

2.ClassPathXmlApplicationContext是一个类,实现了上述功能

3.ApplicationContext的顶层接口是BeanFactory

4.BeanFactory定义了bean相关的最基本操作

5.ApplicationContext在BeanFactory基础上追加了若干新功能

对比BeanFactory

1.BeanFactory创建的bean采用延迟加载形式,使用才创建

2.ApplicationContext创建的bean默认采用立即加载形式

FileSystemXmlApplicationContext

可以加载文件系统中任意位置的配置文件,而ClassPathXmlApplicationContext只能加载类路径下的配置文件

BeanFactory

Resource res = new ClassPathResource("applicationContext.xml");
BeanFactory bf = new XmlBeanFactory(res);    //XmlBeanFactory已过时
UserService userService = (UserService)bf.getBean("userService");

ClassPathXmlApplicationContext:从类路径中加载 XML 配置文件创建 ApplicationContext

FileSystemXmlApplicationContext:从文件系统中加载 XML 配置文件创建 ApplicationContext

AnnotationConfigApplicationContext:基于注解配置创建 ApplicationContext

WebApplicationContext:用于在 Web 应用程序中加载和管理组件

4.第三方资源配置(bean的配置方式)

阿里数据源方案Druid

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
    <property name="url" value="jdbc:mysql://localhost:3306/spring_ioc"></property>
    <property name="username" value="root"></property>
    <property name="password" value="ljb"></property>
</bean>

样例

<dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
    </dependencies>
<?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:util="http://www.springframework.org/schema/util"
       xmlns:set="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       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">
    
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/spring_ioc"></property>
        <property name="username" value="root"></property>
        <property name="password" value="123456"></property>
    </bean>

</beans>

import com.alibaba.druid.pool.DruidDataSource;
import com.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserApp {
    public static void main(String[] args) {
        //加载配置文件
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取资源
        //UserService userService = (UserService) ctx.getBean("userService");

        //userService.save();

        DruidDataSource dataSource = (DruidDataSource) ctx.getBean("dataSource");
        System.out.println(dataSource);
    }
}

5.案例:Spring整合Mybatis 

案例介绍

使用spring整合mybatis技术,完成账户模块(Account)的基础增删改查功能

账户模块对应字段

        编号:id

        账户名:name

        余额:money

非spring环境

1.实体类与表

2.业务层接口与实现

3.数据层接口

4.Mybatis核心配置

5.Mybatis映射配置

6.客户端程序测试功能

spring环境

1.实体类与表

2.业务层接口与实现(提供数据层接口的注入操作)

3.数据层接口

4.Mybatis核心配置(交给spring控制,该文件省略)

5.Mybatis映射配置

6.客户端程序测试功能(使用spring方式获取bean)

7.Spring核心配置文件

8.Druid数据源的应用(可选)

9.Spring整合Mybatis

基础准备工作

环境准备

1.导入Spring坐标,MyBatis坐标,MYSQL坐标,Druid坐标

业务类与接口准备

2.创建数据库表,并制作相应的实体类Account

3.定义业务层接口与数据层接口

4.在业务层调用数据层接口。并实现业务方法的调用

基础配置文件

5.jdbc.properties

6.Mybatis映射配置文件

整合准备工作

1.spring配置文件,加上context命名空间,用于加载properties文件

2.开启加载properties文件

3.配置数据源Druid(备用)

4.定义service层bean,注入dao层bean

5.dao的bean无需定义,使用代理自动生成

整合工作

1.导入Spring整合Mybatis坐标

2.将mybatis配置成spring管理的bean(SqlSessionFactoryBean)

        将原始配置文件中的所有项,转入到当前配置中

                数据源转换

                映射转换

3.通过spring加载mybatis的映射配置文件到spring环境中

4.设置类型别名

5.测试结果;使用spring环境加载业务层bean,执行操作

 <dependencies>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-jdbc</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.3</version>
        </dependency>
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.30</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>1.3.0</version>
        </dependency>
    </dependencies>
package com.dao;

import com.domain.Account;


import java.util.List;

public interface AccountDao {
    void save (Account account);
    void delete (Integer id);
    void update (Account account);
    List<Account> findAll ();
    Account findById (Integer id);
}
package com.domain;


public class Account {
    private Integer id;
    private String name;
    private Double money;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}
package com.service;

import com.domain.Account;

import java.util.List;

public interface AccountService {
    void save (Account account);
    void delete (Integer id);
    void update (Account account);
    List<Account> findAll ();
    Account findById (Integer id);
}
package com.service.impl;

import com.dao.AccountDao;
import com.domain.Account;
import com.service.AccountService;

import java.util.List;

public class AccountServiceImpl implements AccountService {
    private AccountDao accountDao;

    public void setAccountDao(AccountDao accountDao) {
        this.accountDao = accountDao;
    }


    public void save(Account account) {
        accountDao.save(account);
    }


    public void delete(Integer id) {
        accountDao.delete(id);
    }


    public void update(Account account) {
        accountDao.update(account);
    }


    public List<Account> findAll() {

        return accountDao.findAll();
    }


    public Account findById(Integer id) {

        return accountDao.findById(id);
    }
}

<?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:util="http://www.springframework.org/schema/util"
       xmlns:set="http://www.springframework.org/schema/util"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:context="http://www.springframework.org/schema/context"
       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">

    <!--加载properties配置文件的信息-->
    <context:property-placeholder location="classpath:*.properties"/>

    <!--加载druid资源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>
    <!--配置service作为spring的bean,注入dao-->
    <bean id="accountService" class="com.service.impl.AccountServiceImpl">
        <property name="accountDao" ref="accountDao"/>
    </bean>
    <!--spring整合mybatis后控制的创建连接用的对象-->
    <bean  class="org.mybatis.spring.SqlSessionFactoryBean">
        <property name="dataSource" ref="dataSource"/>
        <property name="typeAliasesPackage" value="com.domain"/>
    </bean>
    <!--加载mybatis映射配置的扫描,将其作为spring的bean进行管理-->
    <bean  class="org.mybatis.spring.mapper.MapperScannerConfigurer">
        <property name="basePackage" value="=com.dao"/>
    </bean>

</beans>

jdbc.properties 

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&useSSL=false
jdbc.username=root
jdbc.password=123456

AccountDao.xml

<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis的DTD约束-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mapper:核心根标签;namespace属性:名称空间-->
<mapper namespace="com.dao.AccountDao">
    <!--select:查询功能的标签
        id属性:唯一标识
        resultType属性:指定结果映射对象类型
        parameterType属性:指定参数映射对象类型-->
    <!--配置根据id查询-->
    <select id="findById" resultType="account" parameterType="int">
        SELECT * FROM account WHERE id = #{id}
    </select>
    <!--配置查询所有-->
    <select id="findAll" resultType="account">
        SELECT * FROM account
    </select>
    <!--配置保存-->
    <insert id="save" parameterType="account">
        INSERT INTO account(name, money) VALUES (#{name},#{money})
    </insert>
    <!--配置更新-->
    <update id="update" parameterType="account">
        UPDATE account SET name = #{name},money = #{money} WHERE id = #{id}
    </update>
    <!--配置删除-->
    <delete id="delete" parameterType="int">
        DELETE FROM account WHERE id = ${id}
    </delete>
</mapper>
import com.domain.Account;
import com.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class App {
    public static void main(String[] args) {
        //加载配置文件
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        AccountService accountService = (AccountService) ctx.getBean("accountService");
        //Account ac = accountService.findById(1);
        //System.out.println(ac);

        Account account = new Account();
        account.setName("Tom");
        account.setMoney(123456.78);
        accountService.save(account);
    }
}

6..注解开发

1.注解的概述

什么是注解驱动

注解启动时使用注解的形式替代xml配置,将繁杂的spring配置文件从工程中彻底消除掉,简化书写

注解驱动的弊端

为了达成注解驱动的目的,可能会将原先很简单的书写,变的更加复杂

XML中配置第三方开发的资源是很方便的,但使用注解驱动无法在第三方开发的资源中进行编辑,因此会增大开发工作量

2.bean定义的常用注解

启动注解功能

启动注解扫描,加载类中配置的注解项

<context:component-scan base-package="packageName"/>

说明:

在进行包所扫描时,会对配置的包及其子包中所有文件进行扫描

扫描过程是以文件夹递归迭代的形式进行的

扫描过程仅读取合法的java文件

扫描时仅读取spring可识别的注解

扫描结束后会将可识别的有效注解转化为spring对应的资源加入IoC容器

注意:

无论是注解格式还是XML配置格式,最终都是将资源加载到IoC容器中,差别仅仅是数据读取方式不同

从加载效率上来说注解优于XML配置文件

bean的定义

名称:@Component @Controller @Service @Repository

类型:类注解

位置:类定义上方

作用:设置该类为spring管理的bean

范例

@Component
public class ClassName{}

说明:

@Controller、@Service 、@Repository是@Component的衍生注解,功能同@Component

相关属性

value(默认):定义bean的访问id

bean的作用域

名称:@Scope

类型:类注解

位置:类定义上方

作用:设置该类作为bean对应的scope属性

范围

@Scope
public class ClassName{}

相关属性

value(默认):定义bean的作用域,默认为singleton

bean的生命周期

名称:@PostConstruct、@PreDestroy

类型:方法注解

位置:方法定义上方

作用:设置该类作为bean对应的生命周期方法

范例

@PostConstruct
public void init() { System.out.println("init..."); }

样例

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

    <!--启动注解驱动,指定对应扫描的路径,也就是资源所在的包-->
    <context:component-scan base-package="com"/>
    <!--<bean id="userService" class="com.service.impl.UserServiceImpl"/>-->
    <!--<bean id="userDao" class="com.dao.impl.UserDaoImpl"/>-->
    <!--<bean id="bookDao" class="com.dao.impl.BookDaoImpl"/>-->
</beans>

package com.service.impl;

import com.service.UserService;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

//定义bean,后面添加bean的id
@Component("userService")
//设定bean的作用域
@Scope("singleton")
public class UserServiceImpl implements UserService {
    public void save(){
        System.out.println("user service running...");
    }
    //设定bean的生命周期
    @PostConstruct
    public void init(){
        System.out.println("user service init...");
    }
    //设定bean的生命周期
    @PreDestroy
    public void destroy(){
        System.out.println("user service destroy...");
    }

}
package com.dao.impl;

import com.dao.UserDao;
import org.springframework.stereotype.Component;

@Component("userDao")
public class UserDaoImpl implements UserDao {
    public void save(){
        System.out.println("user dao running...");
    }
}
package com.dao.impl;

import com.dao.BookDao;
import org.springframework.stereotype.Component;

@Component("bookDao")
public class BookDaoImpl implements BookDao {
   public void save(){
       System.out.println("book dao running...");
   }
}
import com.dao.BookDao;
import com.dao.UserDao;
import com.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserApp {
    public static void main(String[] args) {
        //加载配置文件
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取资源
        UserService userService = (UserService) ctx.getBean("userService");
        userService.save();

        UserDao userDao = (UserDao) ctx.getBean("userDao");
        userDao.save();

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();
    }
}

3.加载第三方资源

名称:@Bean

类型:方法注解

位置:方法定义上方

作用:设置该方法的返回值作为spring管理的bean

范例

@Bean("dataSource")
public DruidDataSource createDataSource() {    return ……;    }

说明:

因为第三方bean无法在其源码上进行修改,使用@Bean解决第三方bean的引入问题

该注解用于替代XML配置中的静态工厂与实例工厂创建bean,不区分方法是否为静态或非静态

@Bean所在的类必须被spring扫描加载,否则该注解无法生效

相关属性

value(默认):定义bean的访问id

样例

新建com.config.JDBCConfig

package com.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;

@Component
public class JDBCConfig {
    @Bean("dataSource")
    public DruidDataSource getDataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("root");
        ds.setUsername("root");
        ds.setPassword("123456");
        return ds;
    }
}
    <dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.1.9.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.16</version>
        </dependency>
    </dependencies>
import com.alibaba.druid.pool.DruidDataSource;
import com.dao.BookDao;
import com.dao.UserDao;
import com.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserApp {
    public static void main(String[] args) {
        //加载配置文件
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取资源
        UserService userService = (UserService) ctx.getBean("userService");
        userService.save();

        UserDao userDao = (UserDao) ctx.getBean("userDao");
        userDao.save();

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();

        DruidDataSource dataSource = (DruidDataSource) ctx.getBean("dataSource");
        System.out.println(dataSource);
    }
}

4.属性注入常用注解

1.bean的非引用类型属性注入

名称:@Value

类型:属性注解、方法注解

位置:属性定义上方,方法定义上方

作用:设置对应属性的值或对方法进行传参

范围

@Value("${jdbc.username}")
private String username;

说明:

value值仅支持非引用类型数据,赋值时对方法的所有参数全部赋值

value值支持读取properties文件中的属性值,通过类属性将properties中数据传入类中

value值支持SpEL

@value注解如果添加在属性上方,可以省略set方法(set方法的目的是为属性赋值)

相关属性:

value(默认):定义对应的属性值或参数值

样例

package com.service.impl;

import com.service.UserService;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

//定义bean,后面添加bean的id
@Component("userService")
//设定bean的作用域
@Scope("singleton")
public class UserServiceImpl implements UserService {
    @Value("3")
    private int num;
    @Value("ljb")
    private String version;

   /* public void setNum(int num) {
        this.num = num;
    }

    public void setVersion(String version) {
        this.version = version;
    }*/

    public void save(){
        System.out.println("user service running..."+num+" "+version);
    }
    //设定bean的生命周期
    @PostConstruct
    public void init(){
        System.out.println("user service init...");
    }
    //设定bean的生命周期
    @PreDestroy
    public void destroy(){
        System.out.println("user service destroy...");
    }

}

2.bean的引用类型属性注入

名称:@Autowired、@Qualifier

类型:属性注解、方法注解

位置:属性定义上方,方法定义上方

作用:设置对应属性的对象或对方法进行引用类型传参

范例

@Autowired(required = false)
@Qualifier("userDao")
private UserDao userDao;

说明

@Autowired默认按类型装配,指定@Qualifier后可以指定自动装配的bean的id

相关属性

required:定义该属性是否允许为null

package com.service.impl;

import com.dao.UserDao;
import com.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

//定义bean,后面添加bean的id
@Component("userService")
//设定bean的作用域
@Scope("singleton")
public class UserServiceImpl implements UserService {
    //非引用类型
    @Value("3")
    private int num;
    @Value("ljb")
    private String version;
    //引用类型
    @Autowired
    private UserDao userDao;

   /* public void setNum(int num) {
        this.num = num;
    }

    public void setVersion(String version) {
        this.version = version;
    }*/

    public void save(){
        System.out.println("user service running..."+num+" "+version);
        userDao.save();
    }

    //设定bean的生命周期
    @PostConstruct
    public void init(){
        System.out.println("user service init...");
    }
    //设定bean的生命周期
    @PreDestroy
    public void destroy(){
        System.out.println("user service destroy...");
    }

}
import com.alibaba.druid.pool.DruidDataSource;
import com.dao.BookDao;
import com.dao.UserDao;
import com.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserApp {
    public static void main(String[] args) {
        //加载配置文件
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取资源
        UserService userService = (UserService) ctx.getBean("userService");
        userService.save();

        UserDao userDao = (UserDao) ctx.getBean("userDao");
        userDao.save();

//        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
//        bookDao.save();

//        DruidDataSource dataSource = (DruidDataSource) ctx.getBean("dataSource");
//        System.out.println(dataSource);
    }
}

名称:@Primary

类型:类注解

位置:类定义上方

作用:设置类对应的bean按类型装配时优先装配

范例

@Primary
public class ClassName{}

@Autowired默认按类型装配,当出现相同类型的bean,使用@Primary提高按类型自动装配的优先级,多个@Primary会导致优先级设置无效

名称:@Inject、@Named、@Resource

说明:

@Inject与@Named是JSR330规范中的注解,功能与@Autowired和@Qualifier完全相同,适用于不同架构场景

@Resource是JSR250规范中的注解,可以简化书写格式

@Resource相关属性

name:设置注入的bean的id

type:设置注入的bean的类型,接收的参数为Class类型

5..加载properties文件 

名称:@PropertySource

类型:类注解

位置:类定义上方

作用:加载properties文件中的属性值

范例

@PropertySource(value = "classpath:filename.properties")
public class ClassName {
    @Value("${propertiesAttributeName}")
    private String attributeName;
}

说明:

不支持*通配格式,一旦加载,所有spring控制的bean中均可使用对应属性值

相关属性

value(默认):设置加载的properties文件名

ignoreResourceNotFound:如果资源未找到,是否忽略,默认为false

样例

package com.dao.impl;

import com.dao.BookDao;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;

@Component("bookDao")
@PropertySource(value={"classpath:jdbc.properties","classpath:abc.properties"},ignoreResourceNotFound = true)
public class BookDaoImpl implements BookDao {
    @Value("${jdbc.userName}")
    private String userName;
    @Value("${jdbc.password}")
    private String password;
    public void save(){
        System.out.println("book dao running..."+userName+" "+password);
    }
}
import com.alibaba.druid.pool.DruidDataSource;
import com.dao.BookDao;
import com.dao.UserDao;
import com.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserApp {
    public static void main(String[] args) {
        //加载配置文件
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //获取资源
        UserService userService = (UserService) ctx.getBean("userService");
        userService.save();

        UserDao userDao = (UserDao) ctx.getBean("userDao");
        userDao.save();

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();

        DruidDataSource dataSource = (DruidDataSource) ctx.getBean("dataSource");
        System.out.println(dataSource);
    }
}

6.纯注解格式

名称:@Configuration、@ComponentScan

类型:类注解

位置:类定义上方

作用:设置当前类为spring核心配置加载类

范例

@Configuration
@ComponentScan("scanPackageName")
public class SpringConfigClassName{
}

说明:

核心配合类用于替换spring核心配置文件,此类可以设置空的,不设置变量与属性

bean扫描工作使用注解@ComponentScan替代

AnnotationConfigApplicationContext

加载纯注解格式上下文对象,需要使用AnnotationConfigApplicationContext

AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);

样例

 在config包下新建SpringConfig来代替applicationContext.xml

package com.config;

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

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

import com.alibaba.druid.pool.DruidDataSource;
import com.config.SpringConfig;
import com.dao.BookDao;
import com.dao.UserDao;
import com.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserApp {
    public static void main(String[] args) {
        //加载配置文件
        //ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        //获取资源
        UserService userService = (UserService) ctx.getBean("userService");
        userService.save();

        UserDao userDao = (UserDao) ctx.getBean("userDao");
        userDao.save();

        BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        bookDao.save();

        DruidDataSource dataSource = (DruidDataSource) ctx.getBean("dataSource");
        System.out.println(dataSource);
    }
}

7.第三方bean配置与管理

名称:@Import

类型:类注解

位置:类定义上方

作用:导入第三方bean作为spring控制的资源

范例

@Configuration
@Import(OtherClassName.class)
public class ClassName {
}

说明

@Import注解在同一个类上,仅允许添加一次,如果需要导入多个,使用数组的形式进行设定

在被导入的类中可以继续使用@Import导入其他资源(了解)

@Bean所在的类可以使用导入的形式进入spring容器,无需声明为bean

样例

package com.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;


public class JDBCConfig {
    @Bean("dataSource")
    public DruidDataSource getDataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("root");
        ds.setUsername("root");
        ds.setPassword("123456");
        return ds;
    }
}
package com.config;

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

@Configuration
@ComponentScan("com")
@Import(JDBCConfig.class)
public class SpringConfig {
}
import com.alibaba.druid.pool.DruidDataSource;
import com.config.SpringConfig;
import com.dao.BookDao;
import com.dao.UserDao;
import com.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserApp {
    public static void main(String[] args) {
        //加载配置文件
        //ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        //获取资源
        UserService userService = (UserService) ctx.getBean("userService");
        userService.save();

        //UserDao userDao = (UserDao) ctx.getBean("userDao");
        //userDao.save();

        //BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        //bookDao.save();

        DruidDataSource dataSource = (DruidDataSource) ctx.getBean("dataSource");
        System.out.println(dataSource);
    }
}

8.bean加载控制

1.@DependsOn

名称:@DependsOn

类型:类注解、方法注解

位置:bean定义的位置(类上或方法上)

作用:控制bean的加载顺序,使其在指定bean加载完毕后再加载

范例

@DependsOn("beanId")
public class ClassName {
}

说明:

配置在方法上,使@DependsOn指定的bean优先于@Bean配置的bean进行加载

配置在类上,使@DependsOn指定的bean优先于当前类中所有@Bean配置的bean进行加载

配置在类上,使@DependsOn指定的bean优先于@Component等配置的bean进行加载

相关属性:

value(默认):设置当前bean所依赖的bean的id

样例

package com.service.impl;

import com.dao.BookDao;
import com.dao.UserDao;
import com.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;

//定义bean,后面添加bean的id
@Component("userService")
//设定bean的作用域
@Scope("singleton")

public class UserServiceImpl implements UserService {
    public UserServiceImpl(){
        System.out.println("service running...");
    }
    //非引用类型
    @Value("3")
    private int num;
    @Value("ljb")
    private String version;
    //引用类型
    @Qualifier("userDao")
    @Autowired
    private UserDao userDao;
    @Autowired
    private BookDao bookDao;


    public void save(){
        System.out.println("user service running..."+num+" "+version);
        userDao.save();
    }

    //设定bean的生命周期
    @PostConstruct
    public void init(){
        System.out.println("user service init...");
    }
    //设定bean的生命周期
    @PreDestroy
    public void destroy(){
        System.out.println("user service destroy...");
    }

}
package com.dao.impl;


import com.dao.UserDao;
import org.springframework.stereotype.Component;


@Component("userDao")
public class UserDaoImpl implements UserDao {

    public UserDaoImpl() {
        System.out.println("dao running...");
    }
    public void save(){
        System.out.println("user dao running...");
    }
}

 

现在要改变顺序 

package com.dao.impl;

import com.dao.UserDao;
import org.springframework.context.annotation.DependsOn;
import org.springframework.stereotype.Component;

@Component("userDao")
@DependsOn("userService")
public class UserDaoImpl implements UserDao {

    public UserDaoImpl() {
        System.out.println("dao running...");
    }
    public void save(){
        System.out.println("user dao running...");
    }
}

2.@Order

名称:@Order

类型:配置类注解

位置:配置类定义的位置(类上)

作用:控制配置类的加载顺序

范例

@Order(1)
public class SpringConfigClassName {
}

样例

package com.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;

@Configuration
@ComponentScan("com")
@Import(JDBCConfig.class)
@Order(1)
public class SpringConfig {
    @Bean("b1")
    public String getB1(){
        System.out.println("b1");
        return "";
    }
}
package com.config;

import com.sun.xml.internal.messaging.saaj.soap.ver1_1.Body1_1Impl;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Import;
import org.springframework.core.annotation.Order;

import java.util.SplittableRandom;

@Configuration
@ComponentScan("com")
@Import(JDBCConfig.class)
@Order(2)
public class SpringConfig2 {
        @Bean("b2")
        public String getB1(){
        System.out.println("b2");
        return "";
        }
}
import com.alibaba.druid.pool.DruidDataSource;
import com.config.SpringConfig;
import com.config.SpringConfig2;
import com.dao.BookDao;
import com.dao.UserDao;
import com.service.UserService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class UserApp {
    public static void main(String[] args) {
        //加载配置文件
        //ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class, SpringConfig2.class);
        //获取资源
        UserService userService = (UserService) ctx.getBean("userService");
        userService.save();

        //UserDao userDao = (UserDao) ctx.getBean("userDao");
        //userDao.save();

        //BookDao bookDao = (BookDao) ctx.getBean("bookDao");
        //bookDao.save();

        //DruidDataSource dataSource = (DruidDataSource) ctx.getBean("dataSource");
        //System.out.println(dataSource);
    }
}

控制b1与b2的输出顺序数字越小越先输出

3.@Lazy

名称:@Lazy

类型:类注解、方法注解

位置:bean定义的位置(类上或方法上)

作用:控制bean的加载时机,使其延迟加载

范例

@Lazy
public class ClassName {
}

加载控制的应用场景

@DependsOn

微信订阅号,发布消息和订阅消息的bean的加载顺序控制

双11活动期间,零点前是结算策略A,零点后是结算策略B,策略B操作的数据为促销数据。策略B加载顺序与促销数据的加载顺序

@Lazy

程序灾难出现后对应的应急预案处理是启动容器时加载时机

@Order

多个种类的配置出现后,优先加载系统级的,然后加载业务级的,避免细粒度的加载控制

7.案例:注解整合Mybatis

注解整合Mybatis分析

业务类使用注解形式声明bean,属性采用注解注入

建立独立的配置管理类,分类管理外部资源,根据功能进行分类,并提供对应的方法获取bean

使用注解形式启动bean扫描,加载所有注解配置的资源(bean)

使用AnnotationConfigApplicationContext对象加载所有的启动配置类,内部使用导入方式进行关联

注解整合Mybatis步骤

1.修改mybatis外部配置文件格式为注解格式(删掉Mybatis映射配置文件,在dao层基于注解开发) 

2.业务类使用@Component 声明bean,使用@Autowired 注入对象

3.建立配置文件JDBCConfig与MybatisConfig类,并将其导入到核心配置类SpringConfig

4.开启注解扫描

5.使用AnnotationConfigApplicationContext对象加载配置项,测试成功

package com.config;

import com.alibaba.druid.pool.DruidDataSource;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;

import javax.sql.DataSource;

public class JDBCConfig {
    @Value("${jdbc.driver}")
    private String driver;
    @Value("${jdbc.url}")
    private String url;
    @Value("${jdbc.username}")
    private String userName;
    @Value("${jdbc.password}")
    private String password;
    @Bean("dataSource")
    public DataSource getDataSource(){
        System.out.println(driver);
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driver);
        ds.setUrl(url);
        ds.setUsername(userName);
        ds.setPassword(password);
        return ds;
    }
}

package com.config;

import org.mybatis.spring.SqlSessionFactoryBean;
import org.mybatis.spring.mapper.MapperScannerConfigurer;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;

import javax.sql.DataSource;

public class MyBatisConfig {
    @Bean
    public SqlSessionFactoryBean getSqlSessionFactoryBean(@Autowired DataSource dataSource){
        SqlSessionFactoryBean ssfb = new SqlSessionFactoryBean();
        ssfb.setTypeAliasesPackage("com.domain");
        ssfb.setDataSource(dataSource);
        return ssfb;
    }
    @Bean
    public MapperScannerConfigurer getMapperScannerConfigurer(){
        MapperScannerConfigurer msc = new MapperScannerConfigurer();
        msc.setBasePackage("com.dao");
        return msc;
    }
}
package com.config;

import org.springframework.context.annotation.*;

@Configuration
@ComponentScan("com")
@PropertySource("classpath:jdbc.properties")
@Import({JDBCConfig.class,MyBatisConfig.class})
public class SpringConfig {
}
package com.dao;

import com.domain.Account;

import java.util.List;

public interface AccountDao {
    void save (Account account);
    void delete (Integer id);
    void update (Account account);
    List<Account> findAll ();
    Account findById (Integer id);
}

package com.domain;


public class Account {
    private Integer id;
    private String name;
    private Double money;

    public Integer getId() {
        return id;
    }

    public void setId(Integer id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public Double getMoney() {
        return money;
    }

    public void setMoney(Double money) {
        this.money = money;
    }

    @Override
    public String toString() {
        return "Account{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", money=" + money +
                '}';
    }
}

package com.service.impl;

import com.dao.AccountDao;
import com.domain.Account;
import com.service.AccountService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.util.List;
@Service("accountService")
public class AccountServiceImpl implements AccountService {
    @Autowired
    private AccountDao accountDao;


    public void save(Account account) {
        accountDao.save(account);
    }


    public void delete(Integer id) {
        accountDao.delete(id);
    }


    public void update(Account account) {
        accountDao.update(account);
    }


    public List<Account> findAll() {

        return accountDao.findAll();
    }


    public Account findById(Integer id) {

        return accountDao.findById(id);
    }
}
package com.service;

import com.domain.Account;

import java.util.List;

public interface AccountService {
    void save (Account account);
    void delete (Integer id);
    void update (Account account);
    List<Account> findAll ();
    Account findById (Integer id);
}
import com.config.SpringConfig;
import com.domain.Account;
import com.service.AccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

public class App {
    public static void main(String[] args) {

        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        AccountService accountService = (AccountService) ctx.getBean("accountService");
        Account ac = accountService.findById(2);
        System.out.println(ac);
    }
}

AccountDao.xml 

<?xml version="1.0" encoding="UTF-8" ?>
<!--MyBatis的DTD约束-->
<!DOCTYPE mapper
        PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN"
        "http://mybatis.org/dtd/mybatis-3-mapper.dtd">
<!--mapper:核心根标签;namespace属性:名称空间-->
<mapper namespace="com.dao.AccountDao">
    <!--select:查询功能的标签
        id属性:唯一标识
        resultType属性:指定结果映射对象类型
        parameterType属性:指定参数映射对象类型-->
    <!--配置根据id查询-->
    <select id="findById" resultType="account" parameterType="int">
        SELECT * FROM account WHERE id = #{id}
    </select>
    <!--配置查询所有-->
    <select id="findAll" resultType="account">
        SELECT * FROM account
    </select>
    <!--配置保存-->
    <insert id="save" parameterType="account">
        INSERT INTO account(name, money) VALUES (#{name},#{money})
    </insert>
    <!--配置更新-->
    <update id="update" parameterType="account">
        UPDATE account SET name = #{name},money = #{money} WHERE id = #{id}
    </update>
    <!--配置删除-->
    <delete id="delete" parameterType="int">
        DELETE FROM account WHERE id = ${id}
    </delete>
</mapper>

jdbc.properties 

jdbc.driver=com.mysql.cj.jdbc.Driver
jdbc.url=jdbc:mysql://localhost:3306/spring_db?serverTimezone=UTC&useUnicode=true&characterEncoding=UTF-8&useSSL=false
jdbc.username=root
jdbc.password=123456

整合Junit

如何在Junit中使用spring中的资源 

1.Spring接管Junit的运行权,使用Spring专用的Junit类加载器

2.为Junit测试用例设定对应的spring容器

注意:

从Spring5.0以后,要求Junit的版本必须是4.12及以上

Junit仅用于单元测试,不能将Junit的测试类配置成spring的bean,否则该配置将会被打包进入工程中

导入Junit

        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.13.2</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-test</artifactId>
            <version>5.1.19.RELEASE</version>
        </dependency>

在test目录下创建测试类

package com.service;

import com.config.SpringConfig;
import com.domain.Account;
import org.junit.Assert;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import java.util.List;

//设定spring专用的类加载器
@RunWith(SpringJUnit4ClassRunner.class)
//设定加载的spring上下文对应的配置
@ContextConfiguration(classes = SpringConfig.class)
public class UserServiceTest {
    @Autowired
    private AccountService accountService;
    @Test
    public void testFindById(){
        Account ac = accountService.findById(2);
        //System.out.println(ac);
        Assert.assertEquals("Jock",ac.getName());
    }
    @Test
    public void testFindAll(){
        List<Account> list = accountService.findAll();
        Assert.assertEquals(2,list.size());
    }
}

  • 45
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值