Spring的重新学习

Posted 纯正肉包

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Spring的重新学习相关的知识,希望对你有一定的参考价值。

使用spring框架建立一个项目

1.建立一个maven项目,在pom中加入Spring的框架的依赖。

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

 

2.使用xml来配置你所需要的bean对象,下文给的例子放在了显示层来创建bean对象

3.xml配置了,显示层来创建bean对象的方法也有两种,如图

IAccountService as  = (IAccountService)ac.getBean("accountService");
IAccountDao adao = ac.getBean("accountDao",IAccountDao.class);

 

 

 

 

 

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

    <!--把对象的创建交给spring来管理,就是这里配置的-->
    <bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl"></bean>

    <bean id="accountDao" class="com.itheima.dao.impl.AccountDaoImpl"></bean>
</beans>

 

 

package com.itheima.dao.impl;

import com.itheima.dao.IAccountDao;

/**
 * 账户的持久层实现类
 */
public class AccountDaoImpl implements IAccountDao {

    public  void saveAccount(){

        System.out.println("保存了账户");
    }
}
package com.itheima.dao;

/**
 * 账户的持久层接口
 */
public interface IAccountDao {

    /**
     * 模拟保存账户
     */
    void saveAccount();
}
package com.itheima.service.impl;

import com.itheima.dao.IAccountDao;
import com.itheima.service.IAccountService;

/**
 * 账户的业务层实现类
 */
public class AccountServiceImpl implements IAccountService {

    private IAccountDao accountDao ;//这里我们原来是private IAccountDao accountDao=new AccountDaoImpl();因为我们完成了工厂模式,进行了xml的《bean》的注解public AccountServiceImpl(){
        System.out.println("对象创建了");
    }

    public void  saveAccount(){
        accountDao.saveAccount();
    }
}
package com.itheima.service;

/**
 * 账户业务层的接口
 */
public interface IAccountService {

    /**
     * 模拟保存账户
     */
    void saveAccount();
}
package com.itheima.ui;

import com.itheima.dao.IAccountDao;
import com.itheima.service.IAccountService;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/**
 * 模拟一个表现层,用于调用业务层
 */
public class Client {

    /**
     * 获取spring的Ioc核心容器,并根据id获取对象
     *
     * ApplicationContext的三个常用实现类:
     *      ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了。(更常用)
     *      FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)
     *
     *      AnnotationConfigApplicationContext:它是用于读取注解创建容器的,是明天的内容。
     *
     * 核心容器的两个接口引发出的问题:
     *  ApplicationContext:     单例对象适用              采用此接口
     *      它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。
     *
     *  BeanFactory:            多例对象使用
     *      它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。
     * @param args
     */
    public static void main(String[] args) {
        //1.获取核心容器对象
        ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
//        ApplicationContext ac = new FileSystemXmlApplicationContext("C:\\\\Users\\\\zhy\\\\Desktop\\\\bean.xml");
        //2.根据id获取Bean对象
        IAccountService as  = (IAccountService)ac.getBean("accountService");
        IAccountDao adao = ac.getBean("accountDao",IAccountDao.class);

        System.out.println(as);
        System.out.println(adao);
        as.saveAccount();


        //--------BeanFactory----------
//        Resource resource = new ClassPathResource("bean.xml");
//        BeanFactory factory = new XmlBeanFactory(resource);
//        IAccountService as  = (IAccountService)factory.getBean("accountService");
//        System.out.println(as);
    }
}

 问题:spring提供了几种工厂呢?

  两种:1.上述的applicationContext

     2.使用Beanfactory

  他们什么区别?

  一个适合单例模式,一个适合多例模式

  

问题:xml是配置了,你怎么找到你的xml呢?

 一、三种找到你xml的方法

  高大上一点就是Application的三种实现类

  

一、通俗说就是使用   ApplicationContext ac = new ClassPathXmlApplicationContext("bean.xml");
二、通俗说就是使用 ApplicationContext ac = new FileSystemXmlApplicationContext("C:\\\\Users\\\\zhy\\\\Desktop\\\\bean.xml");
//也就是你磁盘上的xml的真实路径,你查查在你磁盘哪里
三、就是使用注解的方法 在方法上加@xxxxx这种

 问题:你的xml也找到了,如何在xml中配置bean呢?也就是文艺的叫做三种创建bean的方法

  

 

   

 

tip:第一种用于你写的bean类

  第二种用于jar包中bean类,你想使用jar包的,你不可能找到它的工厂,所以我们使用工厂的方法,即factory-bean

  第三种和第二种一样,都是jar包中的,这种特殊在是static关键字修饰的类,但是使用方法同第二种

 

    id属性: 指定对象在容器中的标识,用于从容器中获取对象
    class属性: 指定静态工厂的全类名
    factory-method属性: 指定生产对象的静态方法

 

 问题:bean既然配置了,它的使用范围有多大呢?

 这个是bean上的《Scope》属性

 

 

 解释一下:

  1.单例,默认,就是你创建的bean是单例模式,只会创建一个对象来处理我们所有的请求,比如Dao和Service

  2.多例,就是你创建的bean是多例模式,在使用bean时会创建很多对象来处理我们的请求

  3.request,请求,就是你向服务器请求,要求服务器为你干啥的时候有用

  4.session,就是你俩已经建立了关系,你俩商量,我要啥,服务器说我要啥,咱俩沟通沟通

  5.集群,就是大型网络供应商,服务器有很多台,他们都处理客户端的请求,因为有很多人访问,这时候中间会加一个东西,叫负载均衡来帮助分发请求。

 

问题,你bean创建完了,什么时候销毁呢?

 

 

 别忘了,容器就是你第一句先获取的AplicationContext对象

 

问题:你先在一个个的bean做好了,他们之间的关系怎么交给Spring呢?

也就是依赖注入

依赖注入:Dependency Injection。它是 spring 框架核心 ioc 的具体实现。
我们的程序在编写时,通过控制反转,把对象的创建交给了 spring,但是代码中不可能出现没有依赖的情况。
ioc 解耦只是降低他们的依赖关系,但不会消除。例如:我们的业务层仍会调用持久层的方法。
那这种业务层和持久层的依赖关系,在使用 spring 之后,就让 spring 来维护了。
简单的说,就是坐等框架把持久层对象传入业务层,而不用我们自己去获取。
 
三种方法
1.在xml中配置
2.使用set方法
3.注解
 
1.xml配置
顾名思义,就是使用类中的构造函数,给成员变量赋值。注意,赋值的操作不是我们自己做的,而是通过配置
的方式,让 spring 框架来为我们注入。具体代码如下:
/**
  适用场景,不经常变的数据,如用户姓名,性别等,
  缺点,只要是配置的属性,就比如传入,比如你在网页上使用这种方法,用户就必须填写用户名。
*/ public class AccountServiceImpl implements IAccountService { private String name; private Integer age; private Date birthday; public AccountServiceImpl(String name, Integer age, Date birthday) { this.name = name; this.age = age; this.birthday = birthday; } @Override public void saveAccount() { System.out.println(name+","+age+","+birthday); } } <!-- 使用构造函数的方式,给 service 中的属性传值 要求: 类中需要提供一个对应参数列表的构造函数。 涉及的标签: constructor-arg 属性: index:指定参数在构造函数参数列表的索引位置 type:指定参数在构造函数中的数据类型 name:指定参数在构造函数中的名称 用这个找给谁赋值
=======上面三个都是找给谁赋值,下面两个指的是赋什么值的==============

value:它能赋的值是基本数据类型和 String 类型 ref:它能赋的值是其他 bean 类型,也就是说,必须得是在配置文件中配置过的 bean -->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<constructor-arg name="name" value="张三"></constructor-arg>
<constructor-arg name="age" value="18"></constructor-arg>
<constructor-arg name="birthday" ref="now"></constructor-arg>//复杂类 </bean>
<bean id="now" class="java.util.Date"></bean>

2.set方法

顾名思义,就是在类中提供需要注入成员的 set 方法。具体代码如下:另外对于复杂类来说,相同类型复杂类,可以互换
List 结构的
array,list,set
Map 结构的
map,entry,props,prop

<property name="myStrs">
  <set>//这也可以写成<list>,或者<array>
    <value>AAA</value>
    <value>BBB</value>
    <value>CCC</value>
  </set>
</property>
/** */
public class AccountServiceImpl implements IAccountService {
private String name;//小写
private Integer age;
private Date birthday;
public void setName(String name) {//大写,可以使用快捷键1.光标在类里面,按alt+insert。弹出一个小窗,可以用它生成多种代码。 2.点击getter与setter这个 3.现在弹出一个小窗,让你选择给哪个生成set和get方法 
this.name = name; }
public void setAge(Integer age) {
this.age = age; }
public void setBirthday(Date birthday) {
this.birthday = birthday; }
@Override
public void saveAccount() {
System.out.println(name+","+age+","+birthday);
} }
<!-- 通过配置文件给 bean 中的属性传值:使用 set 方法的方式
涉及的标签:
property
属性:
name:找的是类中 set 方法后面的部分
ref:给属性赋值是其他 bean 类型的
value:给属性赋值是基本数据类型和 string 类型的
实际开发中,此种方式用的较多。
-->
<bean id="accountService" class="com.itheima.service.impl.AccountServiceImpl">
<property name="name" value="test"></property> //小写
<property name="age" value="21"></property>
<property name="birthday" ref="now"></property> </bean>
<bean id="now" class="java.util.Date"></bean>

3.使用注解的方法

你说上述这种bean文件太麻烦了,有没有简单的。答案是有

怎么做?查阅官方文档,找到注解的xml的写法

1.xml中的文件改成,请和原来的xml进行比较,basepackage就是你所希望写类的包的路径

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

    <!--告知spring在创建容器时要扫描的包,配置此项所需标签不在beans的约束中,而在一个名为context的名称空间和约束中-->
    <context:component-scan base-package="cn.maoritian"></context:component-scan>
</beans>

 

 

 2.在类的开始加上注解@component

 

 

3.常用注解
用于创建对象的注解

这些注解的作用相当于bean.xml中的<bean>标签

    @Component: 把当前类对象存入spring容器中,其属性如下:
        value: 用于指定当前类的id. 不写时默认值是当前类名,且首字母改小写
    @Controller: 将当前表现层对象存入spring容器中
    @Service: 将当前业务层对象存入spring容器中
    @Repository: 将当前持久层对象存入spring容器中
  这三个的注解的作用和属性与@Component是一模一样的,可以相互替代,它们的作用是使三层对象的分别更加清晰.

 

问题:我们已经通过@component等注解告诉ioc容器有这几个bean,如何使用注解进行数据注入呢?

Service肯定需要Dao层,因为要拿出数据。

上述我们使用的时set构造函数进行的注入,我们想使用注解

就需要@autowired注解进行数据注入,也就是在变量对象上加上注解。

 

 

 

 

问题:它是如何进行注入的呢?

Dao接口会去找实现类进行注入。如果有DaoImpl1和DaoImpl2两个实现类,该找哪个?就会报错了。所以也就是Dao只能有唯一一个实现类!

 

问题:现在我就是有两个实现类,他们有不同的功能,你怎么处理?

先回忆一下。@Component(“变量名”)这个注解没忘记把,

那就使用@qualifier注解进行指定,它不能单独使用,必须指定@Component后跟的变量名,并且配合@Autowired使用

 

 这他麻烦了,我不想记。你就可以使用@resource注解,使用方法如下

@resource(name=“bean名字”)

 

 

问题:如何确定bean的使用范围

使用@Scope,放在类的头上就是对整个类有用,放在方法上,就是对方法有用

 

总结:

 

 

问题:如何替代xml中的配置呢?

在使用xml配置中,我们是用


<context:component-scan base-package="cn.maoritian"></context:component-scan>

我们现在不在xml中配置了,我们建一个config类。充当xml的角色。

使用注解

@configuration代表这是一个配置类

@component-scan来代表应该去哪里找bean

 

 

问题:@Bean是干什么的呢?

导入junit的依赖

 

 

 

 这里的@Autowired注解,没有用。注入不进去,使用@RunWith,表示junit把原有的方法替换了。

 

 问题:如何在config.class这个配置类中动态的配置jdbc链接

描述:我们希望改的时候只改jdbc的链接和密码,而不动代码

我们可以设置一个变量来存储,然后使用properties文件存储我们的用户名和密码

这样下次需要改动的时候我们只需要改动properties文件即可,实现了解耦

那么我们如何将properties和我们的config.class联系,

就是在congfig类加个注解

@propertySource(properties的路径)

这个properties的文件一般新建在resource中,也就是properties相对于resource的路径

 

 


 

 

以上是关于Spring的重新学习的主要内容,如果未能解决你的问题,请参考以下文章

重新创建片段布局

重新创建活动后片段不可见

片段中的Firebase数据不是持久的,会重新下载

重新加载时刷新片段

Asynctask结果显示重新创建片段后

重新打开片段时应用程序崩溃