Skip to content
kcp edited this page Jul 13, 2020 · 3 revisions

title: Spring date: 2018-12-21 10:46:01 tags: - Spring categories: - Java

目录 start

  1. Spring
    1. 配置使用
      1. 通过构建工具
      2. 注解方式
        1. xml文件配置
        2. 常用的注解
      3. xml方式
        1. xml方式和注解方式的比较
    2. Spring技巧
      1. 获取Context上下文环境
        1. 在JSP或Servlet中获取
      2. Spring 和 ServletContextList
  2. 基础
    1. 生命周期
    2. IOC/DI 控制反转
    3. Scheduling
    4. Events
    5. Websocket
      1. maven配置
    6. Utils
      1. ReflectionUtils
  3. Web开发的最佳实践

目录 end|2020-04-27 23:42|


Spring

Spring官网 | spring4all社区

Spring For All 社区 -> Spring 官方教程翻译

Spring Tutorial

配置使用

通过原始的复制jar方式 : 官网下载对应的jar, 添加到ide中

通过构建工具

Maven 中 pom.xml 中, Gradle是 build.gradle 添加以下等依赖:

核心依赖

  1. spring-core
  2. spring-beans
  3. spring-context

其他,可选

  1. spring-aop
  2. spring-websocket
  3. spring-jdbc
  4. spring-tx
  5. spring-web
  6. spring-webmvc
  7. spring-test

注解方式

需要在配置文件 xml配置文件 中配置包扫描 才能生效

xml文件配置

    <!-- 头部分要添加Context -->
    <?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-3.0.xsd">
        <!-- 对使用了注解的包进行扫描 -->
        <context:component-scan base-package="com.github.kuangcp"></context:component-scan>
    </beans>

注意 只需要这个配置文件就可以使用注解来使用Spring框架

常用的注解

  • 标注为bean

    • @Component([value=]"id") 不写则默认是当前类名
    • @Entity
    • @Service
    • @Repository
    • @Controller 和 @RestController
  • 自动注入

    • @Resource([value=]"id") 按名字注入
    • @Autowried 根据类型自动注入(只对单例起作用)和 Resource(类名首字母小写) 等价
      • 通过阅读源码还可以知道 可以将符合条件的Bean注入到 List 和 Map 中去, 甚至 Optional
    • @Qualifier("id") 自动注入后的进一步精确(多个Bean的情况:)
  • 注意 : 关于自动注入, 在属性上打 @Autowried 注解是不建议的, 作者建议采用构造器方式: Why field injection is evil

    • 如果使用了 lombok 那么可以在类上使用
      • @RequiredArgsConstructor(onConstructor = @__(@Autowired))
      • 然后注入的属性打上 @NonNull 注解
      • 本质上是帮你自动生成了一个将所有 @NonNull 注解属性作为参数的构造器
  • AOP

    • @Aspect 注明是切面类
    • @Before("execution(public void com.wjt276.dao.impl.UserDaoImpl.save(com.wjt276.model.User))") 和xml方式的before对应
  • bean扫描

    • ComponentScan 扫描指定包下Spring注解的类

参考: Why field injection is evil


xml方式

  • 只用到bean的头,主要配置内容:<bean><property></property></bean>
    <!-- 对使用了注解的包进行扫描 -->
	<context:component-scan base-package="cn.spring.aop"></context:component-scan>
       <!-- 一般而言,bean都是单实例的 -->
    <bean id="person" class="cn.spring.entity.Person"> 
        <property name="name" value="myth"/>
        <property name="addr" value="vol"/>
    </bean>
    <bean id="construct" class="cn.spring.entity.ConstructorEntity">
    <!-- 如果是不同的类型的参数 顺序可以随意,但是数据类型一样的话就要严格按顺序了-->
    <constructor-arg type="java.lang.String" value="String_1"></constructor-arg>
        <!-- 注意引用类型是要写全路径,基本数据类型是可以直接写小写 -->
    <constructor-arg type="int" value="2"></constructor-arg>
        <!-- <constructor-arg type="java.lang.String" value="String_2"></constructor-arg> -->
    </bean>
    <bean id="TestConstruct" class="cn.spring.entity.TestConstruct">
        <property name="entity" ref="construct"></property>
    </bean>
    <!-- 加载属性文件 -->
    <bean id="property_config" class="org.springframework.beans.factory.config.PreferencesPlaceholderConfigurer">
        <property name="locations">
            <list>
                <value>cn/spring/entity/db.properties</value>
            </list>
        </property>
    </bean>
    <!-- 测试获取属性文件 -->
    <bean id="show_db" class="cn.spring.entity.TestProperties">
        <!-- 特别注意大小写问题 -->
        <property name="driver" value="${driver}"/>
        <property name="username" value="${username}"/>
        <property name="password" value="${password}"/>
        <property name="url" value="${url}"/>
    </bean>

xml方式和注解方式的比较

  • 当你确定切面是实现一个给定需求的最佳方法时,你如何选择是使用Spring AOP还是AspectJ,以及选择 Aspect语言(代码)风格、@AspectJ声明风格或XML风格?
  • 这个决定会受到多个因素的影响,包括应用的需求、 开发工具和小组对AOP的精通程度。
  • 个人理解:使用bean的时候使用注解,AOP使用xml方式,更直观

Spring技巧

获取Context上下文环境

在JSP或Servlet中获取

    ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(config.getServletContext());

Spring 和 ServletContextList

  • 想要启动Tomcat之后,初始化运行一些方法,把数据从数据库拿出放入redis中,然后使用了ServletContextListener
    • 然后还是按照往常一样的使用Spring自动注入的便利,来使用service层获取数据,但是忽略了启动顺序
    • context-param -> listener -> filter -> servlet
    • 所以在启动这个初始化方法的时候,其实Spring的环境是还没有加载的,所以没有扫描,也就没有了自动注入,也就有了空指针异常
    • 所以要使用如下方法得到Spring的Context(上下文),获取bean,再操作
    public void contextInitialized(ServletContextEvent event) { 
        ApplicationContext context = WebApplicationContextUtils.getWebApplicationContext(event.getServletContext());
        //....
    }

基础

生命周期

  • @PreDestroy
  • @PostConstruct

IOC/DI 控制反转

  • DI 译为依赖注入 所有的bean都在IOC容器中(单例的)多例的不在该容器中进行管理
  • 通过注入 可以注入基本属性 对象属性,集合属性,构造器,properties等
  • 不采用Spring的IOC容器使用Java基础来实现:
    • 静态代理
      • 针对每个具体类分别编写代理类
      • 针对一个接口编写一个代理类
    • 动态代理
      • 针对一个方面编写一个InvocationHandler,然后借用JDK反射包中的Proxy类为各种接口动态生成相应的代理类

属性上 @Autowired 即可, 但是现在不建议直接在属性上使用注解, 而是建议用在构造器上
这是为了避免NPE: 当手动使用 new 实例化Bean, 里面本该注入的属性是会为null

使用Lombok简化该方式

    @Component
    @RequiredArgsConstructor(onConstructor = @__(@Autowired))
    public class A{
        @NonNull
        private B b;
    }

Scheduling

Official Doc

参考: The @Scheduled Annotation in Spring
参考: Spring Scheduler的使用与坑 参考: [Spring]支持注解的Spring调度器 参考: spring scheduled的动态线程池调度和任务进度的监控

其主体是 TaskExecutor 和 TaskScheduler 组成的, 也就是调度和执行


Events

Spring Events

Synchronous and Asynchronous Spring Events in One Application
@EventListener with @Async in Spring

异步事件处理

  • 类上 @EnableAsync 方法上 @Async 并指定配置的线程池名字

参考: spring线程池(同步、异步)

Websocket

maven配置

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

Utils

ReflectionUtils


Web开发的最佳实践

  • 使用AOP来简化开发MVC的代码
  • 繁杂的代码如何简化

Tips

Summary

Clone this wiki locally