Spring学习



1. Spring

1.1 简介

  1. 2002年首次推出了spring雏形 interface21
  2. spring框架即以interface21框架为基础经过重新设计,不断丰富内涵,于2004年3月24日发布了1.0正式版本
  3. spring理念:使现有的技术更加容易使用,本身是一个大杂烩,整合了现有的技术框架
  • SSH: Struct2 + Spring + Hibernate
  • SSM: SpringMVC + Spring + Mybatis

官网:https://spring.io/projects/spring-framework#learn
下载:https://repo.spring.io/release/org/springframework/spring/
导包:

<!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-webmvc</artifactId>
    <version>5.3.7</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-jdbc -->
<dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.7</version>
</dependency>
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
        </dependency>
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.10</version>
        </dependency>

1.2 优点

  • 开源、免费容器
  • 轻量级、非入侵式框架
  • 控制反转(IOC), 面向切面编程(AOP)
  • 支持事务处理,对框架整合的支持

** 总结一句话:Spring就是一个轻量级的控制反转(IOC)和面向切面编程的容器**

1.3 组成

  1. 核心容器(Spring Core)

核心容器提供Spring框架的基本功能。Spring以bean的方式组织和管理Java应用中的各个组件及其关系。Spring使用BeanFactory来产生和管理Bean,它是工厂模式的实现。BeanFactory使用控制反转(IoC)模式将应用的配置和依赖性规范与实际的应用程序代码分开。

  1. 应用上下文(Spring Context)

Spring上下文是一个配置文件,向Spring框架提供上下文信息。Spring上下文包括企业服务,如JNDI、EJB、电子邮件、国际化、校验和调度功能。

  1. Spring面向切面编程(Spring AOP)

通过配置管理特性,Spring AOP 模块直接将面向方面的编程功能集成到了 Spring框架中。所以,可以很容易地使 Spring框架管理的任何对象支持 AOP。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖 EJB 组件,就可以将声明性事务管理集成到应用程序中。

  1. JDBC和DAO模块(Spring DAO)

JDBC、DAO的抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理,和不同数据库供应商所抛出的错误信息。异常层次结构简化了错误处理,并且极大的降低了需要编写的代码数量,比如打开和关闭链接。

  1. 对象实体映射(Spring ORM)

Spring框架插入了若干个ORM框架,从而提供了ORM对象的关系工具,其中包括了Hibernate、JDO和 IBatis SQL Map等,所有这些都遵从Spring的通用事物和DAO异常层次结构。

  1. Web模块(Spring Web)

Web上下文模块建立在应用程序上下文模块之上,为基于web的应用程序提供了上下文。所以Spring框架支持与Struts集成,web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。

  1. MVC模块(Spring Web MVC)

MVC框架是一个全功能的构建Web应用程序的MVC实现。通过策略接口,MVC框架变成为高度可配置的。MVC容纳了大量视图技术,其中包括JSP、POI等,模型来有JavaBean来构成,存放于m当中,而视图是一个街口,负责实现模型,控制器表示逻辑代码,由c的事情。Spring框架的功能可以用在任何J2EE服务器当中,大多数功能也适用于不受管理的环境。Spring的核心要点就是支持不绑定到特定J2EE服务的可重用业务和数据的访问的对象,毫无疑问这样的对象可以在不同的J2EE环境,独立应用程序和测试环境之间重用。

1.4 拓展

在Spring官网介绍:现代化的java开发

  • Spring Boot
    • 一个快速开发的脚手架
    • 基于Spring boot可以快速的开发单个微服务
    • 约定大于配置
  • Spring Cloud
    • Spring Cloud是基于SpringBoot实现的

学习SpringBoot前提是学会Spring和SpringMVC
弊端:发展太久,违背了原来的理念,配置繁琐(后来出现了SpringBoot)

2. IOC理论推导

  1. UserDao接口
  2. UserDaoMapper实现类(UserDaoImpl)
  3. UserService 业务接口
  4. UserServiceImpl业务实现类

之前与用户对接的业务层变化不大,而Dao层经常因为业务变动,添加一个实现类,修改一次成本十分昂贵
通过添加setUserDao接口,发生了革命性变化

    //利用set进行动态实现值的注入
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
  • 之前,程序是主动创建对象,控制权在程序员手上
  • 使用set注入后,程序不再具有主动性,而是变成了被动接受对象

这种思想 , 从本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 . 这也就是IOC的原型 !

3. HelloSpring

4. IOC创建对象的方式


xml配置文件读取完成,ioc就已经完成了对象创建

5.Spring配置

5.1 别名

    <bean id="user2" class="com.junyipan.pojo.User2">
        <constructor-arg name="name" value="测试"/>
    </bean>
    
    <alias name="user2" alias="sdfawaefwaew"/>
    static ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");

    @Test
    // 有参构造
    public void initUser2(){
        User2 user2 = (User2) context.getBean("sdfawaefwaew");
        user2.show();
    }

5.2 Bean配置

<!--    id: bean唯一标志符-->
<!--    class:bean对象所对应的全限定名:包名+类型-->
<!--    name:也是别名,而且name可以同时取多个别名,分隔符可以同时用,;-->
    <bean id="user2" class="com.junyipan.pojo.User2" name="user22,dsfwe;ewfew aaaa">
        <constructor-arg name="name" value="测试"/>
    </bean>

5.3 import

import一般用于团队开发,可以将多个配置文件,导入合并为一个

例如有beans1.xml, beans2.xml, beans3.xml,最后在一个ApplicationContext.xml文件中用import解决
注意:同名id的bean会被覆盖

6. 依赖注入(DI)

bean | ref | idref | list | set | map | props | value | null

6.1 构造器注入

c命名空间注入

6.2 set方式注入【重点】

p命名空间注入就是使用的set方式注入

  • 依赖注入:set注入
    • 依赖:bean对象创建依赖于容器
    • 注入:bean对象所有属性由容器来注入

【环境搭建】
1. 复杂类型

public class Student {
    private String name;
    private Address address;
    private String[] books;
    private List<String> hobbies;
    private Map<String, String> card;
    private Set<String> games;
    private String wife;
    private Properties info;
}
2. 真实测试对象
3. 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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="student" class="com.junyipan.pojo.Student">
<!--        第一种,普通值注入-->
        <property name="name" value="熊仔"/>

    </bean>
    <!-- more bean definitions go here -->

</beans>
4. 测试类
import com.junyipan.pojo.Student;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void test01(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
//        Student student = (Student) context.getBean("student");
        Student student = context.getBean(Student.class);
        System.out.println(student);
    }
}

6.3 拓展方式注入

我们可以用p命名空间和c命名空间注入

1. 声明pojo

package com.junyipan.pojo;

public class User {
    private String name;
    private int age;

    public User() {
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "name="" + name + """ +
                ", age=" + age +
                "}";
    }
}

2.使用

<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd">
<!--    p命名空间注入,可以直接注入属性的值(set)  p命名空间即property命名空间-->
    <bean id="user" class="com.junyipan.pojo.User" p:age="18" p:name="熊仔"/>
<!--    c命名空间注入,通过构造器注入:constructor-args-->
    <bean id="user2" class="com.junyipan.pojo.User" c:age="18" c:name="熊仔2" />
</beans>

3.测试

    @Test   // p命名空间注入
    public void test02(){
        ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
        User user = context.getBean("user", User.class);
        System.out.println(user);
    }


    @Test   // c命名空间注入
    public void test03(){
        ApplicationContext context = new ClassPathXmlApplicationContext("userbeans.xml");
        User user = context.getBean("user2", User.class);
        System.out.println(user);
    }

** 注意点:p命名和c命名空间不能直接使用,需要在xml的header中导入p约束和c约束**

       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"

6.4 bean的作用域

bean中定义属性scope,默认是singleton单例模式,还有prototype原型模式,session模式, request模式

  1. 单例模式
<bean id="user2" class="com.junyipan.pojo.User" c:age="18" c:name="熊仔2"  scope="singleton"/>
  1. 原型模式:每次从容器中get时候,都会生成一个新对象
<bean id="user4" class="com.junyipan.pojo.User" c:age="18" c:name="熊仔4" scope="prototype"/>
  1. 其余的request,session,application都只能在web开发中才能用到

7. bean的自动装配

  • 自动装配式spring满足bean依赖的一种方式
  • spring会在上下文中自动寻找,并自动给bean装配

在spring中有三种装配方式:

  1. 在xml中显式装配
  2. 在java中显式装配
  3. 隐式自动装配bean【重要】

7.1 测试

  1. 环境搭建
    • person,一个人有2个宠物
public class Person {
    private Cat cat;
    private Dog dog;
    private String name;
}

7.2 byName

<?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="cat" class="com.junyipan.pojo.Cat"/>
    <bean id="dog" class="com.junyipan.pojo.Dog"/>
    <bean id="person" class="com.junyipan.pojo.Person">
        <property name="name" value="俊逸"/>
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
    </bean>
    <!-- more bean definitions go here -->
    <bean id="person2" class="com.junyipan.pojo.Person" autowire="byName">
    </bean>
</beans>

7.3 byType

<?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="cat" class="com.junyipan.pojo.Cat"/>
    <bean id="dog222" class="com.junyipan.pojo.Dog"/>
    <bean id="person" class="com.junyipan.pojo.Person">
        <property name="name" value="俊逸"/>
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog222"/>
    </bean>
    <!-- more bean definitions go here -->
    <bean id="person2" class="com.junyipan.pojo.Person" autowire="byType">
    </bean>
</beans>
  • byName会自动再容器上下文中查找和自己对象set方法后面的值相同的bean id
  • byType会自动再容器上下文中查找和自己对象set方法后面的类型相同的bean id

小结:

  • byName需要保证所有bean的id唯一,会自动再容器上下文中查找,且这个bean需要和自动注入的属性对应的set方法的值一致
  • byType需要保证所有bean的class唯一,会自动再容器上下文中查找,且这个bean需要和自动注入的属性的类型一致

7.4 使用注解实现自动装配

jdk1.5支持的注解,Spring2.5就支持注解了

要使用注解须知:

  1. 导入context约束
  2. 配置注解支持
<?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/context
        https://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>

@Autowired

  1. 直接在属性上使用即可,也可以在set方法上使用
  2. 优先按类型自动装配,如果找不到就报错,找到多个则按名字匹配,还是找不到就报错
  3. 使用之后,不需要再写set方法了,前提是自动装配的属性在IOC容器中存在,且符合byType + byName
  4. 如果@Autowired(required=true)中的required(默认为true)显式定义了为false,则代表该属性值可以为null,否则不可为null。 required=false也可以通过@Nullable实现相同效果
  5. 如果@Autowired自动装配的环境比较复杂,无法通过一个注解完成时,可以使用@Qualifier(value=”xxx”)来配合使用指定一个唯一的对象
  6. @Resource或@Resource(name=”xxx”)和@Autowired是一样的效果

小结:
@Autowired和@Resource区别:

  • 都是用来自动装配的,都可以放在属性字段上
  • @Autowired优先通过byType方式装配,如果找不到报错,找到多个则byName区别
  • @Resource默认通过byName方式实现,如果找不到,则通过byType

8. 使用注解开发

在spring4之后,要使用注解开发,必须要保证aop包导入成功
使用注解需要导入context约束,注解支持

8.1 注解说明

  • @Autowired: 自动装配通过类型、名字
    如果Autowired通过类型取出的不是唯一,则再通过名称匹配,也可以通过@Qualifier(value=”xxxx”)显式指定装配

  • @Nullable:字段标记了这个注解,说明这个字段可以为null

  • @Resource:自动装配通过名字、类型

  • @Component: 组件,放在类上面,说明这个类被spring管理了,就是bean。

    相当于在applicationContext定义好了

	<bean id="user" class="com.junyipan.pojo.User"/>`
  • @Value:相当于在IOC容器中的bean定义了property
    <bean id="user" class="com.junyipan.pojo.User">
        <property name="name" value="熊斌"/>
    </bean>
  1. bean
  2. 属性如何注入
package com.junyipan.pojo;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

@Component  //组件,等价于<bean id="user" class="com.junyipan.pojo.User"/>
public class User {
    @Value("熊斌")
    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "name="" + name + """ +
                "}";
    }
}

  1. 衍生的注解
    @Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层
    – dao 一般会使用【@Repository】注解,效果与@Component相同
    – service 【@Service】
    – controller 【@Controller】
    这四个注解功能都是一致的,都是代表将某个类注册到ioc容器中,将类实例化,交给spring管理,完成bean的注册
  2. 自动装配
- @Autowired: 自动装配通过类型、名字
	如果Autowired通过类型取出的不是唯一,则再通过名称匹配,也可以通过@Qualifier(value="xxxx")显式指定装配
- @Nullable:字段标记了这个注解,说明这个字段可以为null
- @Resource:自动装配通过名字、类型
-  @Component: 组件,放在类上面,说明这个类被spring管理了,就是bean。
		@Component有几个衍生注解,我们在web开发中,会按照mvc三层架构分层
		- dao  一般会使用【@Repository】注解,效果与@Component相同
		- service	【@Service】
		- controller	【@Controller】
	这四个注解功能都是一致的,都是代表将某个类注册到ioc容器中,将类实例化,交给spring管理,完成bean的注册

  1. 作用域@Scope
package com.junyipan.pojo;

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

@Component  //组件,等价于<bean id="user" class="com.junyipan.pojo.User"/>
@Scope("singleton")
public class User {
    @Value("熊斌")
    private String name;


    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "User{" +
                "name="" + name + """ +
                "}";
    }
}

  1. 小结
    xml与注解
    – xml更加万能,适用于任何场合,维护简单方便
    – 注解:不是自己类使用不了,维护相对复杂
    最佳实践:
    – xml用来管理bean
    – 注解只负责完成属性注入
    – 使用过程中,只需要注意:
    xml <context:annotation-config/> <context:component-scan base-package="com.junyipan"/>

9. 使用Java方式配置Spring

完全使用java替代xml
JavaConfig是Spring的一个子项目,在Spring4之后,它成为了一个核心功能
@Configuration @Bean

hmoban主题是根据ripro二开的主题,极致后台体验,无插件,集成会员系统
自学咖网 » Spring学习