wy132
wy132
发布于 2024-07-14 / 2 阅读
0

Spring 6 笔记

1. 入门

1.创建spring6工程,创建spring6-first子模块

image-20240503151147186

2.在父工程pom.xml中引入Sping的基础依赖,子工程也会继承该依赖

<dependencies>
    <!--spring context依赖-->
    <!--当你引入Spring Context依赖之后,表示将Spring的基础依赖引入了-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-context</artifactId>
        <version>6.0.3</version>
    </dependency>
​
    <!--junit5测试-->
    <dependency>
        <groupId>org.junit.jupiter</groupId>
        <artifactId>junit-jupiter-api</artifactId>
        <version>5.3.1</version>
    </dependency>
​
    <!--log4j2的依赖-->
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-core</artifactId>
        <version>2.19.0</version>
    </dependency>
    <dependency>
        <groupId>org.apache.logging.log4j</groupId>
        <artifactId>log4j-slf4j2-impl</artifactId>
        <version>2.19.0</version>
    </dependency>
</dependencies>

3.创建类HelloWorld,包名为package com.atguigu.spring6.bean;

4.在resources目录创建一个 Spring 配置文件 beans.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标签表示将 class指定包下的指定一个类 与id设定的名绑定-->
    <bean id="helloWorld" class="com.atguigu.spring6.bean.HelloWorld"></bean>
</beans>

5.在其他类中使用

    @Test
    public void testHelloWorld(){
        //生成 beans.xml 配置文件的对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("beans.xml");
        //getbean 方法找到指定id对应的类,返回该类
        HelloWorld helloworld = (HelloWorld) ac.getBean("helloWorld");
        //实例化成功,可以使用该类的方法
        helloworld.sayHello();
    }

2. Log4j2日志

在类的根路径下创建log4j2.xml配置文件

<?xml version="1.0" encoding="UTF-8"?>
<configuration>
    <loggers>
        <!--
            level指定日志级别,从低到高的优先级:
                TRACE < DEBUG < INFO < WARN < ERROR < FATAL
                trace:追踪,是最低的日志级别,相当于追踪程序的执行
                debug:调试,一般在开发中,都将其设置为最低的日志级别
                info:信息,输出重要的信息,使用较多
                warn:警告,输出警告的信息
                error:错误,输出错误信息
                fatal:严重错误
        -->
        <root level="DEBUG">
            <appender-ref ref="spring6log"/>
            <appender-ref ref="RollingFile"/>
            <appender-ref ref="log"/>
        </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>
​
        <!--文件会打印出所有信息,这个log每次运行程序会自动清空,由append属性决定,适合临时测试用
            fileName指定存储地址-->
        <File name="log" fileName="d:/spring6_log/test.log" append="false">
            <PatternLayout pattern="%d{HH:mm:ss.SSS} %-5level %class{36} %L %M - %msg%xEx%n"/>
        </File>
​
        <!-- 这个会打印出所有的信息,
            每次大小超过size,
            则这size大小的日志会自动存入按年份-月份建立的文件夹下面并进行压缩,
            作为存档-->
        <RollingFile name="RollingFile" fileName="d:/spring6_log/app.log"
                     filePattern="log/$${date:yyyy-MM}/app-%d{MM-dd-yyyy}-%i.log.gz">
            <PatternLayout pattern="%d{yyyy-MM-dd 'at' HH:mm:ss z} %-5level %class{36} %L %M - %msg%xEx%n"/>
            <SizeBasedTriggeringPolicy size="50MB"/>
            <!-- DefaultRolloverStrategy属性如不设置,
            则默认为最多同一文件夹下7个文件,这里设置了20 -->
            <DefaultRolloverStrategy max="20"/>
        </RollingFile>
    </appenders>
</configuration>

3. 容器:IoC

3.1 基于XML管理Bean

3.1.1 获取Bean

  1. 方法一:根据id获取

    HelloWorld helloworld = (HelloWorld) ac.getBean("helloWorld");
  2. 方法二:根据类型获取

    HelloWorld bean = ac.getBean(HelloWorld.class);
  3. 方法三:根据id和类型获取

    HelloWorld bean = ac.getBean("helloworld", HelloWorld.class);

注意:可以使用接口类型获取Bean

3.1.2 依赖注入

指Spring创建对象的过程中,将对象的属性通过配置进行赋值

setter方法注入:

1.首先,指定类中必须有set方法

2.然后在配置中声明,property标签来给该类的属性赋值,使用set方法

<bean id="studentOne" class="com.atguigu.spring6.bean.Student">
    <!-- property标签:通过组件类的setXxx()方法给组件对象设置属性 -->
    <!-- name属性:指定属性名(这个属性名是getXxx()、setXxx()方法定义的,和成员变量无关) -->
    <!-- value属性:指定属性值 -->
    <property name="id" value="1001"></property>
    <property name="name" value="张三"></property>
    <property name="age" value="23"></property>
    <property name="sex" value="男"></property>
</bean>

3.创建实例:会自动根据配置创建对象,并根据配置来给对象赋值

    ApplicationContext ac = new ClassPathXmlApplicationContext("spring-di.xml");
    Student studentOne = ac.getBean("studentOne", Student.class);
    System.out.println(studentOne);

构造器注入:

同理,原类中需有构造方法,在配置中使用constructor-arg标签,该标签会调用构造方法来赋值

:constructor-arg标签有name属性来指定参数名

<bean id="studentTwo" class="com.atguigu.spring6.bean.Student">
    <constructor-arg value="1002"></constructor-arg>
    <constructor-arg value="李四"></constructor-arg>
    <constructor-arg value="33"></constructor-arg>
    <constructor-arg value="女"></constructor-arg>
</bean>

3.1.3 特殊值处理

null值:

<property name="name"><null /></property>

转义字符:输入< >

<property name="expression" value="a &lt; b"/>

CDATA节:

<property name="expression">
    <value><![CDATA[ 任意字符 ]]></value>
</property>

3.1.4 对象类型赋值

:给一个类中的一个对象属性赋值private Student stu(如类中的这个属性为学生对象)

:使用bean标签里的ref属性

例子:Person类中有Student类的属性,注入:

方法一:引用外部bean

<!--
1.先给Student类配置
2.给Person类注入时,使用ref标签,里面填Student的配置的id
-->
<bean id="student" class="com.bean.Student"></bean>
<bean id="studentFour" class="com.bean.Person">
    <property name="stu" ref="student"></property>
</bean>

方法二:内部bean:property内部写bean来引入

<bean id="studentFour" class="com.atguigu.spring6.bean.Student">
    <property name="clazz">
        <!-- 在一个bean中再声明一个bean就是内部bean -->
        <!-- 内部bean只能用于给属性赋值,不能在外部通过IOC容器获取,因此可以省略id属性 -->
        <bean id="clazzInner" class="com.atguigu.spring6.bean.Clazz">
        </bean>
    </property>
</bean>

方法三:级联赋值

:ref指定对象属性,用id.属性方式,注入

<bean id="studentFour" class="com.atguigu.spring6.bean.Student">
    <property name="clazz" ref="clazzOne"></property>
    <property name="clazz.clazzId" value="3333"></property>
    <property name="clazz.clazzName" value="最强王者班"></property>
</bean>

3.1.5 数组类型赋值

private String[] hobbies;

array标签

    <property name="hobbies">
        <array>
            <value>抽烟</value>
            <value>喝酒</value>
            <value>烫头</value>
        </array>
    </property>

3.1.6 集合类型赋值

List:

private List<Student> students;

list标签

    <property name="students">
        <list>
            <ref bean="studentOne"></ref>
            <ref bean="studentTwo"></ref>
            <ref bean="studentThree"></ref>
        </list>
    </property>

Map:

private Map<String, Teacher> teacherMap;
<bean id="teacherOne" class="com.atguigu.spring6.bean.Teacher"></bean>
<bean id="teacherTwo" class="com.atguigu.spring6.bean.Teacher"></bean>
<bean id="studentFour" class="com.atguigu.spring6.bean.Student">
    <property name="teacherMap">
        <map>
            <entry>
                <key>
                    <value>10010</value>
                </key>
                <ref bean="teacherOne"></ref>
            </entry>
            <entry>
                <key>
                    <value>10086</value>
                </key>
                <ref bean="teacherTwo"></ref>
            </entry>
        </map>
    </property>
</bean>

引入集合类型的bean:是一种给List和Map赋值的方法

:使用util:list、util:map标签必须引入相应的命名空间,在xml头部添加一些东西

<!--list集合类型的bean-->
<util:list id="students">
    <ref bean="studentOne"></ref>
    <ref bean="studentTwo"></ref>
    <ref bean="studentThree"></ref>
</util:list>
<!--map集合类型的bean-->
<util:map id="teacherMap">
    <entry>
        <key>
            <value>10010</value>
        </key>
        <ref bean="teacherOne"></ref>
    </entry>
    <entry>
        <key>
            <value>10086</value>
        </key>
        <ref bean="teacherTwo"></ref>
    </entry>
</util:map>
<bean id="studentFour" class="com.atguigu.spring6.bean.Student">
    <property name="teacherMap" ref="teacherMap"></property>
    <property name="students" ref="students"></property>
</bean>

3.1.7 p命名空间

<!--引入-->
<beans xmlns:p="http://www.springframework.org/schema/p"></beans>
<!--使用-->
<bean id="studentSix" class="com.atguigu.spring6.bean.Student"
    p:id="1006" p:name="小明" p:clazz-ref="clazzOne" p:teacherMap-ref="teacherMap"></bean>

3.1.8 引入外部属性文件

:使用context标签

例子:

  1. 创建外部属性文件,jdbc.properties,内容如下

    jdbc.user=root
    jdbc.password=atguigu
    jdbc.url=jdbc:mysql://localhost:3306/ssm?serverTimezone=UTC
    jdbc.driver=com.mysql.cj.jdbc.Driver
  2. 引入context名词空间,并使用context引入

    <?xml version="1.0" encoding="UTF-8"?>
    <beans xmlns:context="http://www.springframework.org/schema/context"
           xsi:schemaLocation="http://www.springframework.org/schema/context
           http://www.springframework.org/schema/context/spring-context.xsd">
    </beans>
    <context:property-placeholder location="classpath:jdbc.properties"/>
  3. 使用外部文件里的属性,使用${键}方式使用属性

    <bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="url" value="${jdbc.url}"/>
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="username" value="${jdbc.user}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

3.1.9 bean生命周期

可以设定对应的钩子函数

  • bean对象创建(调用无参构造器)

  • 给bean对象设置属性

  • bean的后置处理器(初始化之前)

  • bean对象初始化(需在配置bean时指定初始化方法)

  • bean的后置处理器(初始化之后)

  • bean对象就绪可以使用

  • bean对象销毁(需在配置bean时指定销毁方法)

  • IOC容器关闭

3.1.10 bean的作用域

:在类中多次ac.getBean(该bean)得到A,B,C对象,singleton表示A,B,C为同一个,即A,B,C的Hash地址相同

:而prototype,则A,B,C的Hash地址不同

取值

含义

创建对象的时机

singleton(默认)

在IOC容器中,这个bean的对象始终为单实例

IOC容器初始化时

prototype

这个bean在IOC容器中有多个实例

获取bean时

<!-- scope属性:取值singleton(默认值),bean在IOC容器中只有一个实例,IOC容器初始化时创建对象 -->
<!-- scope属性:取值prototype,bean在IOC容器中可以有多个实例,getBean()时创建对象 -->
<bean class="com.atguigu.spring6.bean.User" scope="prototype"></bean>

3.1.11 FactoryBean

:帮我们把复杂组件创建的详细过程和繁琐细节都屏蔽起来,只把最简洁的使用界面展示给我们

:用来整合Mybatis等框架

使用:

package com.atguigu.spring6.bean;
public class UserFactoryBean implements FactoryBean<User> {
    @Override
    public User getObject() throws Exception {
        return new User();
    }
​
    @Override
    public Class<?> getObjectType() {
        return User.class;
    }
}
<bean id="user" class="com.atguigu.spring6.bean.UserFactoryBean"></bean>

注意:使用bean创建对象时,返回的是User对象,不是UserFactoryBean对象

3.1.12 XML的自动装配

:一种简化对象类型赋值的方法

:使用autowire标签,

例子:给UserController类的对象属性userService赋值

public class UserController {
    private UserService userService;

byType方式:根据类型匹配IOC容器中的某个兼容类型的bean,为属性自动赋值,若在IOC中,没有任何一个兼容类型的bean能够为属性赋值,则该属性不装配,即值为默认值null,若在IOC中,有多个兼容类型的bean能够为属性赋值,则抛出异常

<bean id="userController" class="com.atguigu.spring6.autowire.controller.UserController" autowire="byType"></bean>
<bean id="userService" class="com.atguigu.spring6.autowire.service.impl.UserServiceImpl"></bean>

byName:将自动装配的属性的属性名,作为bean的id在IOC容器中匹配相对应的bean进行赋值

注意byName方法 id 值必须与对象属性名相同

<bean id="userController" class="com.atguigu.spring6.autowire.controller.UserController" autowire="byName"></bean>
<bean id="userService" class="com.atguigu.spring6.autowire.service.impl.UserServiceImpl"></bean>

3.2 基于注解管理bean

3.2.1 使用注解

开启组件扫描:Spring 会自动从扫描指定的包(base-package 值)及其子包下的所有类的注解进行装配

<?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-3.0.xsd
    http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启组件扫描功能-->
    <context:component-scan base-package="com.atguigu.spring6"></context:component-scan>
</beans>

context:component-scan还可以设定 指定要排除的哪些组件,或设定仅扫描指定的组件

3.2.2 将类定义成bean

将类标明,给Ioc容器管理,将类定义成bean

<bean id="druidDataSource" class="com.alibaba.druid.pool.DruidDataSource"></bean>

将类定义成bean:在类上面添加注解@Component@Repository@Service@Controller

注意:四个注解无差异,只是为了区别Dao、Service、Controller层

@Component
public class User {}

3.2.3 属性注入-@Autowired

:为属性注入,默认byType类型装配

:可以标在属性、构造方法、普通方法、形参、注解上

public class User {
    //属性上
    @Autowired
    private UserDao userDao;
    //构造方法上
    public User(UserDao userDao) {
        this.userDao = userDao;
    }
    //普通方法,set方法上
    @Autowired
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
    //形参上
    public UserServiceImpl(@Autowired UserDao userDao) {
        this.userDao = userDao;
    }
}

@Qualifier搭配使用,byName,根据名称进行装配

    @Autowired
    @Qualifier("userDaoImpl") // 指定bean的名字
    private UserDao userDao;

3.2.4 @Resource

:定义类生成bean,注入属性

与@Autowired区别:

  • @Resource注解是JDK扩展包中的,也就是说属于JDK的一部分。所以该注解是标准注解,更加具有通用性。(JSR-250标准中制定的注解类型。JSR是Java规范提案。)

  • @Autowired注解是Spring框架自己的。

  • @Resource注解默认根据名称装配byName,未指定name时,使用属性名作为name。通过name找不到的话会自动启动通过类型byType装配。

  • @Autowired注解默认根据类型装配byType,如果想根据名称装配,需要配合@Qualifier注解一起用。

  • @Resource注解用在属性上、setter方法上。

  • @Autowired注解用在属性上、setter方法上、构造方法上、构造方法参数上。

定义类生成bean:

@Repository("myUserDao")
public class UserDaoImpl implements UserDao {}

属性注入:

    @Resource(name = "myUserDao")
    private UserDao myUserDao;

3.2.5 全注解开发

不再使用spring配置文件了,写一个配置类来代替配置文件

原来:写xml文件,使用ClassPathXmlApplicationContext与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:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
    http://www.springframework.org/schema/beans/spring-beans-3.0.xsd
    http://www.springframework.org/schema/context
            http://www.springframework.org/schema/context/spring-context.xsd">
    <!--开启组件扫描功能-->
    <context:component-scan base-package="com.atguigu.spring6"></context:component-scan>
</beans>
        ApplicationContext context = new ClassPathXmlApplicationContext("Beans.xml");
        UserController userController = context.getBean("userController", UserController.class);
        userController.out();

现在:写配置类,使用AnnotationConfigApplicationContext与配置类建立联系

@Configuration
//指定某个包下使用注解
@ComponentScan("com.atguigu.spring6")
public class Spring6Config {
}
    ApplicationContext context = new AnnotationConfigApplicationContext(Spring6Config.class);
    UserController userController = context.getBean("userController", UserController.class);
    userController.out();

4. 面向切面:AOP

:可以在指定方法调用时,插入一些方法

:利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率

:用户验证、日志管理、事务处理、数据缓存等一些非核心业务,将其抽离出来,做成切面类,哪个方法需要就动态代理方式将其逻辑上,插入到方法中执行

:简化代码:把方法中固定位置的重复的代码抽取出来,让被抽取的方法更专注于自己的核心功能,提高内聚性。

:代码增强:把特定的功能封装到切面类中,看哪里有需要,就往上套,被套用了切面逻辑的方法就被切面给增强了。

4.1通知

:简言之,类似在方法被调用执行周期的钩子函数

  • @Before前置通知:在被代理的目标方法执行

  • @After返回通知:在被代理的目标方法成功结束后执行(寿终正寝

  • @AfterThrowing异常通知:在被代理的目标方法异常结束后执行(死于非命

  • @AfterReturning后置通知:在被代理的目标方法最终结束后执行(盖棺定论

  • @Around环绕通知:使用try...catch...finally结构围绕整个被代理的目标方法,包括上面四种通知对应的所有位置

4.2 例子

  1. 添加spring aop依赖、spring aspects依赖

  2. 创建目标类

    @Component
    public class CalculatorImpl implements Calculator {
        @Override
        public int add(int i, int j) {
            int result = i + j;
            System.out.println("方法内部 result = " + result);
            return result;
        }
    }
  3. 创建切面类,并指定方法,其他通知类似

    // @Aspect表示这个类是一个切面类
    @Aspect
    // @Component注解保证这个切面类能够放入IOC容器
    @Component
    public class LogAspect {
        //@Before注解表示在指定方法中使用前置通知,括号内填切入点表达式,指定切入的目标方法
        @Before("execution(public int com.atguigu.aop.annotation.CalculatorImpl.*(..))")
        public void beforeMethod(JoinPoint joinPoint){
            String methodName = joinPoint.getSignature().getName();
            String args = Arrays.toString(joinPoint.getArgs());
            System.out.println("Logger-->前置通知,方法名:"+methodName+",参数:"+args);
        }
    }
  4. beans.xml中应配置

    <aop:aspectj-autoproxy />
  5. 结果,红色框内为前置通知的效果,

    image-20240505204113173

4.3 切入点表达式

表明在哪个或哪些方法中切入,括号内为切入点表达式

@Before("execution(public int com.atguigu.aop.annotation.CalculatorImpl.*(..))")

写法格式

image-20240505204348892

重用切入点表达式:

:写一个方法,然后切入类的方法中使用

@Pointcut("execution(* com.atguigu.aop.annotation.*.*(..))")
public void pointCut(){}
//在同一切面
@Before("pointCut()")
public void beforeMethod(JoinPoint joinPoint){}
//不同切面
@Before("com.atguigu.aop.CommonPointCut.pointCut()")
public void beforeMethod(JoinPoint joinPoint){}

4.4 切面方法优先级

:相同目标方法上同时存在多个切面时,切面的优先级控制切面的内外嵌套顺序。

使用@Order注解可以控制切面的优先级:

  • @Order(较小的数):优先级高

  • @Order(较大的数):优先级低

4.5 基于xml的AOP

<context:component-scan base-package="com.atguigu.aop.xml"></context:component-scan>
<aop:config>
    <!--配置切面类loggerAspect,该类需在Ioc容器中-->
    <aop:aspect ref="loggerAspect">
        <!--配置切入点-->
        <aop:pointcut id="pointCut" 
                   expression="execution(* com.atguigu.aop.xml.CalculatorImpl.*(..))"/>
        <!--指定切入类的方法做前置通知-->
        <!--aop:before表示前置通知,beforeMethod是切面类的方法-->
        <aop:before method="beforeMethod" pointcut-ref="pointCut"></aop:before>
    </aop:aspect>
</aop:config>

5. Spring整合JUnit

在之前的测试方法中,几乎都能看到以下的两行代码:

ApplicationContext context = new ClassPathXmlApplicationContext("xxx.xml");
Xxxx xxx = context.getBean(Xxxx.class);

这两行代码的作用是创建Spring容器,最终获取到对象,但是每次测试都需要重复编写。针对上述问题,我们需要的是程序能自动帮我们创建容器。从而省去写这两行代码。

做法:

  1. 引入spring对junit的支持相关依赖,和junit依赖

  2. 添加配置文件,添加相关命名空间,命名约束

  3. 测试类中使用SpringJUnitConfig注解

    @SpringJUnitConfig(locations = "classpath:beans.xml")
    public class SpringJUnit5Test {
    ​
        @Autowired
        private User user;
    ​
        @Test
        public void testUser(){
            System.out.println(user);
        }
    }

6. 事务

:Spring框架下的关于数据库的事务知识

6.1 Spring的JDBC封装

:Spring中封装了JDBC的jar包,导入后使用其来对数据库进行操作

:使用包内的jdbcTemplate类的方法进行JDBC

如图,查询数据库数据的方法

image-20240506190110546

6.2 基于注解的声明式事务

添加事务注解@Transactional,表示使用事务执行

@Transactional标识在方法上,则只会影响该方法

@Transactional标识的类上,则会影响类中所有的方法

//括号内设置事务的属性
@Transactional(readOnly = true)
public void buyBook(Integer bookId, Integer userId) {}
  • readOnly:只读,表示该方法操作数据库时只允许读操作,不允许写操作

  • timeout:超时,该事务超过指定时间未提交,则回滚

  • noRollbackForrollbackFor:设置哪种异常回滚,哪种不用回滚

  • isolation:设置隔离级别(参考Mysql)

  • propagation:事务的传播,一个方法调用另一个方法时,其各自的事务的传递规则


7. 资源操作

:Spring中提供了一些接口来获取资源,获取网络资源,本地文件资源,本项目资源(css、img)等

UrlResource类访问网络资源:

Resource的一个实现类,用来访问网络资源,它支持URL的绝对路径。

http:------该前缀用于访问基于HTTP协议的网络资源。

ftp:------该前缀用于访问基于FTP协议的网络资源

file: ------该前缀用于从文件系统中读取资源

ClassPathResource 类访问类路径下资源

该类来访问类加载路径下的资源,即项目的包下的所有类class

FileSystemResource类访问本地资源:

使用 FileSystemResource 来访问文件系统资源并没有太大的优势,因为 Java 提供的 File 类也可用于访问文件系统资源。

使用Resource 作为属性

当资源改变时,需修改代码中的资源路径,麻烦,所以将Resource 作为属性,通过配置注入的方式,更方便的维护资源路径


8. 国际化 i18n

:由于软件发行可能面向多个国家,对于不同国家的用户,软件显示不同语言的过程就是国际化。

:通常来讲,软件中的国际化是通过配置文件来实现的,假设要支撑两种语言,那么就需要两个版本的配置文件。

:Spring 和 java都提供相应的方法

9. 数据校检

在开发中,我们经常遇到参数校验的需求,比如用户注册的时候,要校验用户名不能为空、用户名长度不超过20个字符、手机号是合法的手机号格式等等。如果使用普通方式,我们会把校验的代码和真正的业务处理逻辑耦合在一起,而且如果未来要新增一种校验逻辑也需要在修改多个地方。而spring validation允许通过注解的方式来定义对象校验规则,把校验和业务逻辑分离开,让代码编写更加方便

:Spring提供相应的接口