Spring框架学习(上)

主要内容整合自狂神说spring课程

1. Spring简单介绍
1.1 Spring是什么

​ Spring是一个轻量级的控制反转(IOC)和面向切面编程(AOP)的框架,是为了解决企业级应用开发的复杂性而创建的。

核心描述
IOCInverse of Control 的简写,译为“控制反转”,指把创建对象过程交给 Spring 进行管理。
AOPAspect Oriented Programming 的简写,译为“面向切面编程”。AOP 用来封装多个类的公共行为,将那些与业务无关,却为业务模块所共同调用的逻辑封装起来,减少系统的重复代码,降低模块间的耦合度。另外,AOP 还解决一些系统层面上的问题,比如日志、事务、权限等。
1.2 Spring的优点
  • 方便解耦,简化开发
  • 方便集成各种优秀框架
  • 降低JavaEE API的使用难度
  • 方便程序的测试
  • AOP编程的支持
  • 声明式事务的支持
1.3 Spring的架构模块

在这里插入图片描述
上图中包含了 Spring 框架的所有模块,这些模块可以满足一切企业级应用开发的需求,在开发过程中可以根据需求有选择性地使用所需要的模块。

2. 控制反转(IOC)原理讲解
2.1 概念解释

​ 在传统的 Java 应用中,一个类想要调用另一个类中的属性或方法,通常会先在其代码中通过 new Object() 的方式将后者的对象创建出来,然后才能实现属性或方法的调用。为了方便理解和描述,我们可以将前者称为“调用者”,将后者称为“被调用者”。也就是说,调用者掌握着被调用者对象创建的控制权。

​ IoC 带来的最大改变不是代码层面的,而是从思想层面上发生了“主从换位”的改变。原本调用者是主动的一方,它想要使用什么资源就会主动出击,自己创建;但在 Spring 应用中,IoC 容器掌握着主动权,调用者则变成了被动的一方,被动的等待 IoC 容器创建它所需要的对象(Bean)。

​ 这个过程在职责层面发生了控制权的反转,把原本调用者通过代码实现的对象的创建,反转给 IoC 容器来帮忙实现,因此我们将这个过程称为 Spring 的“控制反转”。

​ 狂神说:控制反转,就是获得依赖对象的方式反转了

2.2 IOC原型——代码说明

​ 首先new一个新的maven项目,在pom.xml中导包;在依赖处导入下面这个包

<dependencies>
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.3.21</version>
        </dependency>
</dependencies>

​ 先创建dao层和service层,通过传统方式调用业务层;

​ 在传统业务中,我们需要根据用户需求的变化来修改代码;而代码量越庞大,代码修改代价就会越高,因此我们需要避免这种情况。

传统业务层代码

public class UserServiceImpl implements UserService{
    //1----传统方法
    private UserDao userDao = new UserDaoMysqlImpl();

    @Override
    public void getUser() {
        userDao.getUser();
    }
}

通过set接口实现

public class UserServiceImpl implements UserService{

    //2----set动态注入
    private UserDao userDao;
    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }

    @Override
    public void getUser() {
        userDao.getUser();
    }
}

​ 之前是程序主动创建对象,控制权掌握在程序员手上;

​ 在set注入之后,程序不具有主动性,而是被动接受,主动权交给客户;

好处:降低系统耦合性,更好实现业务

2.3 如何实现IOC

​ 解耦图解:

img

​ 在 Spring 应用中,Java 对象创建的控制权是掌握在 IoC 容器手里的,其大致步骤如下。

  1. 开发人员通过 XML 配置文件、注解、Java 配置类等方式,对 Java 对象进行定义,例如在 XML 配置文件中使用 标签、在 Java 类上使用 @Component 注解等。
  2. Spring 启动时,IoC 容器会自动根据对象定义,将这些对象创建并管理起来。这些被 IoC 容器创建并管理的对象被称为 Spring Bean。
  3. 当我们想要使用某个 Bean 时,可以直接从 IoC 容器中获取(例如通过 ApplicationContext 的 getBean() 方法),而不需要手动通过代码(例如 new Obejct() 的方式)创建。

img

控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。

2.4 IOC思想的代码实现
2.4.1 HelloSpring

​ 创建hello类—— 新建spring配置文件(xml)—— 新建测试类,获取spring的容器,通过容器获取所需的类

2.4.2 改造原型代码

​ 增加set方法——新建配置文件(xml)—— 注册bean —— 新建测试类,获取spring的容器,通过容器获取所需的类

2.5 IOC创建对象的方式

​ 1.默认方法是使用无参构造创建对象。

​ 2.有参构造有三种方法

​ 有参构造方法1 —————— 下标赋值

    <bean id="user" class="com.spring.pojo.User">
        <constructor-arg index="0" value="小明"/>
    </bean>

​ 有参构造方法2(不建议)—————— 通过类型赋值

<bean id="user" class="com.spring.pojo.User">
        <!--class的值:基本类型可以直接用,引用类型需要全限定名 -->
        <constructor-arg type="java.lang.String" value="小明"/>
</bean>

​ 有参构造方式3 —————— 直接通过参数名赋值

<bean id="user" class="com.spring.pojo.User">
        <constructor-arg name="name" value="小明"/>
</bean>

​ 总结: 在配置文件加载时,spring容器中管理的所有对象都会被初始化;而对象的创建遵循单例模式。

3.Spring配置
3.1 别名
<!--可以使用别名获取到对象    -->
    <alias name="user" alias="people"/>
3.2 Bean的配置
<!--
   id : bean的唯一标识符,也就是相当于我们学的对象名
   cLass : bean对象所对应的全限定名:包名+类型
   name : 也是别名,可以取多个别名(比alias好用很多),多个别名之间可以通过 空格 逗号 分号 做分割
   -->
    <bean id="user" class="com.spring.pojo.User" name="user2,u2 u3;u4" scope="singleton">
    </bean>
3.3 import

​ 一般用于团队开放,可以将多个配置文件导入合并。

​ 即使用时使用总的配置文件,在配置文件中导入其他配置文件

​ 导入格式:

<import resource="beans.xml"/>
4. 依赖注入(DI)
4.1 构造器注入
4.2 set方式注入(重点)

​ set注入是依赖注入的本质

​ 依赖:bean对象的创建依赖于容器

​ 注入:bean对象中的所有属性,由容器来注入

4.3 拓展方式

​ P命名空间和c命名空间

​ 配置文件(需要添加约束):

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

​ 完整配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:p="http://www.springframework.org/schema/p"
       xmlns:c="http://www.springframework.org/schema/c"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

<!--    p命名空间注入,可以直接注入属性    -->
        <bean id="user" class="com.spring.pojo.User" p:name="小明" p:age="18"/>

<!--    c命名注入,通过构造器注入:construct-args    -->
        <bean id="user2" class="com.spring.pojo.User" c:age="18" c:name="小明"/>


</beans>

​ 4.4 bean作用域

img

5. bean的自动装配
  • 自动装配是Spring满足bean依赖的一种方式
  • Spring会在上下文中自动寻找,并自动给bean装配属性

Spring有三种装配方式

  1. ​ 在xml中显示的配置
  2. ​ 在java中显示配置
  3. ​ 隐式的自动装配bean(重要)
5.1 ByName自动装配

需要保证bean的id唯一,并且与set方法的值一致

<!--自动装配1
    byName:会自动在容器上下文中查找,和自己对象set方法后面的值对应的beanid
    -->
<bean id="person" class="com.spring.pojo.Person" autowire="byName">
       <property name="name" value="小明"/>
</bean>
5.1 ByType自动装配

需要保证所有bean的class唯一,类型和set方法的类型一致

<!--自动装配2
    byType:会自动在容器上下文中查找,和自己对象set属性类型(class)相同的bean
-->
<bean id="person" class="com.spring.pojo.Person" autowire="byType">
        <property name="name" value="小明"/>
</bean>
5.2 使用注解实现装配

注解相比于xml哪个方法更好,需要视情况而定

使用注解须知:

​ 1.导入约束

​ 2.配置注解的支持

​ 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:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context
        http://www.springframework.org/schema/context/spring-context.xsd">

    <context:annotation-config/>

</beans>

@Autowired

可以在属性上直接使用,也可以用于set方法上(更推荐)

在属性上使用时,set方法可以被省略,前提是自动装配的属性在IOC中存在

注:Autowired注解是按照类型(ByType)装配依赖对象,如果多个相同类型,可以搭配@Qualifier,再按照id(ByName)装配依赖对象

拓展

@Nullable 字段标记了这个注解,说明这个字段可以为null
public class Person {

//    如果显示定义了Autowired的required属性为false,说明这个对象可以为null,否则不允许为空
    @Autowired(required = false)
    private Cat cat;
    @Autowired
    private Dog dog;
}

如果装配环境复杂,有多个同类的对象需要被自动装配时(ByType无法处理);可以通过

@Qualifier(value=“id”)去辅助配置@Autowired的使用。

@Resource

public class People{
	@Resource(name = "cat2")
	private Cat cat;
	
	@Resource
	private Dog dog;
	
}

区别于@Autowire:@Resource默认使用ByName装配,如果找不到对应的id,则采用ByType的方式,如果找不到对应的类型或者对应的类型有两个及以上,则会报错

6.使用注解开发

要保证aop的包导入,需要导入context约束

@Component:组件,放在类上,说明这个类被spring管理了

而Component有几个衍生注解,根据web开发的mvc分层:

  • dao [@Repository]
  • service [@Service]
  • controller [@Controller]

以上注解的功能都是把类注册到容器中

注解和xml的对比

  • xml 更加万能,维护简单方便
  • 注解 灵活性较差,维护相对复杂

最好的实践方式:

​ xml用于bean的管理,注解负责完成属性的注入。

​ 根据使用环境和实际需求决定

7.使用JavaConfig实现配置

方法1:在配置类中定义一个方法,并使用@Bean注解声明。

public class User {
    private String name;

    public String getName() {
        return name;
    }

    @Value("rax")
    public void setName(String name) {
        this.name = name;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                '}';
    }
}
//@Import(UserConfig2.class)
public class UserConfig {

    /*
    注册一个bean,就相当于之前xml里面的一个bean标签,
    这个方法的名字,就相当于bean标签中的id属性
    这个方法的返回值,就相当于bean标签中的class属性
    */
    @Bean
    public User getUser(){
        return new User();
    }
}
public void test(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(UserConfig.class);
        User bean = (User) context.getBean("getUser");
        System.out.println(bean.getName());
    }

方法2:在Developer类上使用@Component注解,并在配置类上先声明@Configuration,然后再声明@ComponentScan(“User类的路径”),这样会自动扫描@Component并生成Bean。

//@Component的目的是将该类和属性注入
@Component
public class Developer {
    private String language;

    public String getLanguage() {
        return language;
    }

    @Value("java")
    public void setLanguage(String language) {
        this.language = language;
    }

    @Override
    public String toString() {
        return "Developer{" +
                "language='" + language + '\'' +
                '}';
    }
}
//这个也会被Spring容器托管,注册到容器中,因为他本来就是一个@Component,@Configuration代表这是一个配置类,就和我们之前看到的beans.xml是一样的
@Configuration
@ComponentScan("com.spring.pojo")
public class DeveloperConfig {

}
public void test2(){
        AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(DeveloperConfig.class);
        Developer bean = (Developer) context.getBean("developer");
        System.out.println(bean.getLanguage());
    }

如果两种方法都使用,会建两个对象,@Component建立的对象用getBean(“user”)获取,配置类中@Bean声明的用getBean(“getUser”)获取,这两个对象是不同的

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值