Spring入门笔记1

Spring入门笔记1

1. 程序耦合度/spring的作用/ioc的原理

以前的程序存在两点不足:

  1. 诸如一些配置信息写在了类中,编译后改不了了,比如数据库的连接信息,如果是写在类中,以后想换数据库就只能动手改源码。解决办法就是通过读取xml或者properties的方式,编译后xml也还在,以后想修改数据库就可以只改变xml的内容。

  1. 创建对象的时候我们通过new的方式,比如在写service层的时候,我们需要new userDao(),这样子的话,如果没有先写好dao层,或者说两个人负责编写两个层等等,就必须等另一个人先写完,这样就不好。后来我们的解决办法是用工厂模式解耦,将new一个实例交给工厂类。这样确实解耦了,但是工厂类还是要改源码,最好的方式还是像xml一样需要的时候来读取。

这就是所谓的耦合度,在我看来,

spring的ioc称为控制反转,就是解决了new的问题,将对象所在的类的路径写在xml中,需要用到对象的时候通过反射来创建对象,相当于编写了一个工厂类的作用。

spring的di称为依赖注入,就是通过xml的方式给函数中的元素赋值,解决了你不知道何时需要从工厂类中创建一个对象的问题,通过依赖注入来告知你想什么时候创建一个对象,需要用到的时候自动从ioc容器中获取而不是new。


借用网上的一张图

ioc简易理解.png

图片来源https://www.cnblogs.com/superjt/p/4311577.html,这篇博客对IOC的概念讲的很棒


2. 如何通过spring的ioc来创建对象从而代替new

2.1 xml方式

bean.xml

bean.xml.png

service层

service层.png

表现层(当然我们以后整合springmvc时不会在controller里面这么写,而是用spring-web包完成,那是后话了)

表现层.png


2.2 注解方式

关于注解方式,只是方式不同,我们讲思想和概念的时候以xml的方式讲,第7部分统一讲注解方式。


3. ApplicationContext类

3.1 ApplicationContext的三个常用实现类

  • ClassPathXmlApplicationContext:它可以加载类路径下的配置文件,要求配置文件必须在类路径下。不在的话,加载不了。(更常用)

  • FileSystemXmlApplicationContext:它可以加载磁盘任意路径下的配置文件(必须有访问权限)

  • AnnotationConfigApplicationContext:它是用于读取注解创建容器的。


3.2 ApplicationContext(代表ioc)和BeanFactory(代表工厂)加载对象的区别(了解)

了解一下即可

ApplicationContext:单例对象适用

采用此接口,它在构建核心容器时,创建对象采取的策略是采用立即加载的方式。也就是说,只要一读取完配置文件马上就创建配置文件中配置的对象。

ApplicationContext方式.png

BeanFactory:多例对象适用

它在构建核心容器时,创建对象采取的策略是采用延迟加载的方式。也就是说,什么时候根据id获取对象了,什么时候才真正的创建对象。

BeanFactory方式.png

这点我们可以通过一个accountService类的一个构造函数输出一句话来验证。


4. 创建Bean的三种方式

4.1 使用默认构造函数创建

也就是上面那样的

在spring的配置文件中使用bean标签,配以id和class属性之后,且没有其他属性和标签时

采用的就是默认构造函数创建bean对象,此时如果类中没有默认构造函数,则对象无法创建。

使用默认构造函数.png


4.2 使用普通工厂中的方法创建对象(使用某个类中的方法创建对象,并存入spring容器)

比如我们使用了工厂模式,又或者使用了别人的jar包,这时候发现某个类没有默认构造函数,只有带参构造函数或者构造函数交给了工厂类来创建。

getInstance之类的方法.png

这时候就要这样创建对象

使用getInstance之类的方法.png


4.3 使用工厂中的静态方法创建对象(使用某个类中的静态方法创建对象,并存入spring容器)

对于静态方法

静态方法.png

那么需要这样使用

使用静态方法.png


5. bean的作用范围和生命周期(了解)

作用范围

bean的作用范围调整

bean标签的scope属性:

    作用:用于指定bean的作用范围

    取值: 常用的就是单例的和多例的

  • singleton:单例的(默认值)
  • prototype:多例的
  • request:作用于web应用的请求范围
  • session:作用于web应用的会话范围
  • global-session:作用于集群环境的会话范围(全局会话范围),当不是集群环境时,它就是session

scope属性的使用.png

似乎是制定了多例,就会像beanFactory一样在需要时才创建对象


生命周期

  • 单例对象

​ 出生:当容器创建时对象出生

​ 活着:只要容器还在,对象一直活着

​ 死亡:容器销毁,对象消亡

​ 总结:单例对象的生命周期和容器相同


  • 多例对象

​ 出生:当我们使用对象时spring框架为我们创建

​ 活着:对象只要是在使用过程中就一直活着。

​ 死亡:当对象长时间不用,且没有别的对象引用时,由Java的垃圾回收器回收

指定周期方法.png

指定周期方法.png


6. 依赖注入Dependence Injection

我们现在只是在视图层(servlet层)通过ioc创建了对象,可以打印出对象的地址,但是我们是要在service层调用dao的对象,也就是要告诉service层有了dao层的对象,总不能在service层去getBean吧,这样没有解耦还不如直接在service层new dao呢,那怎么办呢?这就是依赖注入的作用


简单的说,依赖注入就是通过xml的方式给函数中的元素赋值

比如这些元素.png

比如我们要在servlet中创建service对象,那我们以前就会new service(name, age, birthday),或者函数没有提供参数构造,只有默认构造,但是暴露了set方法(比如实体类),也是可以的new service() setName() setAge() setBirthday()。

依赖注入也是一样需要依靠这些方法,只是不需要主动调用而已,改为在xml中给参数注入值


6.1 能注入的数据类型:有三类

  • 基本类型和String

  • 其他bean类型(在配置文件中或者注解配置过的bean)

  • 复杂类型/集合类型

三种类型的注入连同下面的注入方式一起讲,往下看


6.2 构造函数注入


6.3 set方法注入(更常用)

6.3.1 基本类型和Bean类型的注入

set方法注入基本类型和bean


6.3.2 复杂(集合类型)的注入

集合类型1.png

集合类型2.png


归为两大类

根据结构划分为两大类.png

同一大类的可以互换,但不要这么做

不要这样做.png


7. 注解方式IOC和DI

其实我们回顾xml方式,其实spring的ioc和di就帮我们完成了如下几件事。

  1. <bean>标签实现了对象的创建(代替了new)

  2. <property>标签实现了数据的注入(代替了调用函数和实参)

  3. scope属性指定了bean的作用范围

  4. init-method和destory-method指出了初始化函数和销毁函数(不重要)


因此我们用注解的方式也会实现这些操作

7.1 要使用注解,必须将bean.xml改成以下约束

1
2
3
4
5
6
7
8
9
10
11
12
13
<?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="com.wjw"></context:component-scan>
</beans>

包名记得改


7.2 @Component

作用:和<bean>标签一样,用于把当前类的对象存入spring容器中

写在类上,要new的类上

其中的value属性就是id,若不指定,默认值为首字母小写类名

由于只有一个属性,所以可以直接写@Component(“accountDao1”)


getBean时的实参就是上面的id

7.2.1 @Controller:一般用在表现层

7.2.2 @Service:一般用在业务层

7.2.3 @Repository:一般用在持久层

以上三个注解他们的作用和属性与Component一模一样。

他们三个是spring框架为我们提供明确的三层使用的注解,使我们的三层对象更加清晰。


7.3 @Autowired

写在调用方的方法/变量上

Autowired为什么叫auto呢,因为他会自动注入,也就是说,如果只有一个dao实现类,那么这个注入会自动根据类型匹配到这个实现类,如下图:

Autowired原理示意图

自动按类型注入:是不管key,直接在value中找类型的

如果有两个dao实现类daoImpl1和daoImpl2,那么会先根据类型找出这两个dao,然后根据key(两个dao实现类的@Repository的id)找到对应的类

Autowired原理示意图2


7.3.1 @Qualifier(value=”accountDaoImpl1”):指定id

也就是说,虽然我有两个dao实现类,但是我只用1个,如果我不想在变量名称里面写dao1 dao2,变量名我就想写accountDao,那就要通过这个@Autowired加上@Qualifier(value=”实现类ioc的id”)

@Qualifier使用方法

另外,只有在Qualifier给变量注入时才需要和Autowired一起写,如果是作为方法参数时是可以单独使用的

在方法上使用


7.3.2 @Resource(name=”accountDaoImpl1”)

如果我不想写两个@,又想实现@Qualifier的功能怎么办,就用这个注解


注意:

以上三个注入都只能注入其他bean类型的数据,而基本类型和String类型无法使用上述注解实现。

另外,集合类型的注入只能通过XML来实现。


7.3.3 @Value(value=${SpEL表达式})

用于注入基本类型和String类型的数据


7.3 @Scope

他们的作用就和在bean标签中使用scope属性实现的功能是一样的

写在类上(@Component下方),用于改变bean的作用范围

取值依然是singleton(默认)

​ prototype

​ …


7.4 @Predistroy和@PostConstruct

他们的作用就和在bean标签中使用init-method和destroy-methode的作用是一样的

写在方法上方,销毁和初始化


以下为完全不用XML的方式


7.5 @Configuration、@Bean、@ComponentScan(basePackages = “com.wjw”)

我们发现,比如要在Service中注入dao则需要在serviceImpl中的定义dao语句上面加上@Autowired。但是有时候我们用的是jar包中的类,比如在queryRunner中传入连接池对象,这时候queryRunner和dataSource都不是我们自己写的类,那要如何注入和放进ioc容器呢?

我们只能自己写一个类创建queryRunner对象并加入ioc容器中

自己写配置类

同时,测试的时候applicationContext要改成注解AnnotationConfigApplicationContext类

测试用例中不再是读取xml

手动写getDatasource方法

这时候bean.xml可以不需要了


7.6 多个配置类和@Import

其实只有一个配置类的时候@Configuration加不加都行(最好加),但是如果有多个配置类,则一定要加,多个配置类实现有三种方式:

  1. 指定多个类座位配置文件,但是这样两个配置类理解成“兄弟关系”,但其实是包含关系

兄弟关系

  1. 配置类a中扫描配置类b的包名,同时配置类b也要有@Configuration

类a中添加类b

  1. @Import,在需要的一个配置类中导入另一个配置类,形成我们理解上的“从属关系”

使用@import


7.7 @PropertySource、@Value

外部加载配置信息

不要写死连接信息,也就是如何通过外部文件(.properties来获取信息,通过SpEL表达式)

如果properties文件在包下那么就classpath:packagename/xxx.properties

classpath: 这是真实路径,文件编译后在target/classes目录下


做完这些一看,哦吼,还不如xml方式,所以最简单的方法是自己写的类用注解,jar包中的类用xml

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×