Spring框架学习记录
近来在做web开发,从spring开始做一些简单的学习。
下面是一些基本的spring概念,在学习时逐步记录下来。
Spring框架学习记录
Spring核心思想
- IOC: inversion of control 控制反转。
- 把创建对象new,对象依赖关联关系交给容器去处理,目的解耦合。
- 我们常见的bean对象,就是交给spring容器管理的对象。Bean默认是单例的,在spring加载时候默认就会创建这些bean对象,无论你用不用,都存在。
- 我们可以通过修改xml中的bean class值,达到修改关联实现类的作用。例如A类中有个B类的对象,这种注入关系,也受到spring的自动管理。
- DI: Dependency Injection 依赖注入
- 运行过程中,动态向其他对象提供其依赖关联对象。其实现机制使用反射。
- AOP:Asepct-Orentid Programming 面向切面编程
部分注解
* @Component 表示该类需要在应用程序中被创建,受到spring容器管理,无需额外new
需要写到实现类上,不要写到接口类上
要解决单接口多继承实现类的歧义性,可使用
1. @Primary 提高实现bean类的优先级,只能有一个primary
2. @Qualifier("xxoo") 别名限定符,在component处声明别名,在autowired进行@Qualifier动态绑定
3. @Component("xxoo") 和上面一样,bean id限定符,在component处声明别名,在autowired进行@Qualifier动态绑定
4. 不指定Qualifier别名,也不指定Component的bean id,使用空id的@Component,则默认bean id是 类名首字母小写。使用时候依然在autowired进行@Qualifier动态绑定
5. 当函数参数类型为父接口类,实现不明时,可以用 @Qualifier("xxoo")来修饰参数,以保证参数为指定子类型对象。
6. 还可以使用 javax 的 Resource(name="xxoo"),来替代spring的 Autowired + Qualifier 做动态绑定
compenent属于基本组件类,为符合web的三层结构,controller -> service -> dao ,所以现在推荐使用 @Controller @Service @Respository 三个业务功能注解,不推荐使用 @Compenent,但对不起,这三个新玩意儿和compenent本质上没区别,就是一个区别功能性的注释。
* @ComponentScan 表示自动发现该应用程序中需要被创建的类,自动扫描需要创建类
注意,默认仅扫描本类所在包以及子包内的compenent。
如需扫描其他包。
1. 需要后面追加包名,例如 @ComponentScan("com.xxoo.project.package")
2. 或者 @ComponentScan(basePackages = {"com.xxoo.project.package1", "com.xxoo.project.package2"}),用来添加多包
3. 或者@ComponentScan(basePackageClasses = {MyClass1.class, MyClass2.class}),这种方式方式是,当我们修改包名时不用修改代码
* @Autowired 自动满足bean之间的依赖,自动装配,自动依赖注入。
使用环境
可适用于构造函数,未使用反射,最为高效
也可适用于setter方法以及普通方法
也可使用于成员变量,最为方便
特殊属性
required=true/false
* @Configuration 表示该类当前是一个配置类,可以做到main和组件扫描进行分离
自动装配方式
三种
隐式自动装配【推荐】
对类标注 @component注解,该类会被作为组件类,spring对该类创建 bean对象
然后,一般创建一个空的配置类,该类进行 @componentScan 注解,该类必须为 @Configuration 类,表示spring将自动扫描该配置类所在包。然后在main中,使用 @ContextConfiguration 去加载配置类来进行使用,使用如下
@ContextConfiguration(classes = AppConfig.class)
一般配套使用 @autowired 进行bean自动装配依赖,加(required=false)进行控制;Qualifier来设置bean的id
通常会注入构造函数或者setter方法
java显式装配
一般是因为第三方库,我们不能修改去源代码加标注。这是需要显式的进行装配。
通常先创建一个javaconfig类,里面不放业务逻辑代码,专门配置所需的bean,例如
@Configuration @ContextConfiguration(locations = {"classpath:spring/spring-dao.xml","classpath:scan.xml"}) public class bbsConfig{ private Postdao postdao; private Userdao userdao; @Bean(name="postservice") public PostService getPost() { return new PostserviceImpl(postdao,userdao); } }
- 此时,@Bean 对configration配置类中,@bean表示需要被自动装配的对象
其使用方式,以及去除多义性的方式和自动装配一模一样。@bean 几乎等同于 @Component, 区别仅仅是后者修饰类(我们有源码,可以修改类代码),而前者@bean修饰一个函数(通常在appConfig配置类中),用这个函数创建第三方类对象。
XML配置方式【不太推荐】,就是在XML文件里面对bean做配置,实现自动依赖注入。一般叫 applicationContext.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"
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
">
<!--
这里就是scan的子包名,相当于 @ComponentScan, 这是XML中启动扫描的方法
-->
<context:component-scan base-package="com.freeknight.demo" />
<!--
这部分描述需要被管理的组件名,相当于 @bean
bean: 描述当前对象需要被spring对象管理
id: 从spring容器中获取对象时候使用该id
class: 需要被管理的对象类别全名
-->
<bean id="service" class="service.MessageService">
</bean>
<bean id="printer" class="service.MessagePrinter">
<!--
这部分描述依赖关系,可以不用额外手动指定。
name 是函数参数名
ref 是上面声明的bean id
-->
<property name="service" ref="service"></property>
</bean>
</beans>
- 其中 bean id 就是bean对象的名字,唯一。
- 其中 bean name是bean的别名,可以有多个别名,用分号空格逗号分开都可以。通过任何一个别名都可以获得对应的bean对象。
- 其中可以通过
元素进行构造函数的依赖注入。同样可以缩减为 “c-” 命名空间。 - 可以复杂类型注入,包括 list, set, map, array, 以及对象ref,基本类型使用 value
- 也可以通过
元素进行属性注入,一般是利用set get方法。一样可以缩减为 “p-” 命名空间。 - 还可以用 util- 命名空间 来做一些普通数据的定义,以方便 p- 注入。
注入后的使用如下:
@ContextConfiguration("classpath:applicationContext.xml")
高级装配
Bean的Scope作用域
前提知识
Bean默认是单例的,无论你获取多少次,拿到的都是一个对象。
但有些时候,我们希望Bean不是单例的,每次获取时能是一个新的对象,我们可以通过设定bean的作用于scope来达成,scope有四个值
singleton 默认,单例,只有一个bean实例
prototype 原型模式,每次注入或通过getbean上下文获取时,都会创建一个新的bean实例
session 会话模式,在web应用中,每个会话会创建一个bean实例
request 请求模式,在web应用中,对每个请求会创建一个bean实例
限制scope
XML中
<bean id="xxoo" class="com.freeknight.demo.xxoo" scope="singleton"> </bean>
- JAVA自动装配中
@Component @Scope("session") // 或者@Scope(ConfigurableBeanFactory.SCOPE_SESSION)均可 public class MyClass{ }
- JAVA手动装配中
@Configration public class AppConfig{ @Bean @Scope("session") public MyClass getMyClass(){ return new MyClass(); } }
延迟加载
前提知识:
在spring加载时候默认就会创建这些bean对象,无论你用不用,都存在。
但有些时候我们不想开始花费时间进行bean对象创建和加载,我们需要使用时按需加载,则需要使用延迟加载,我们就需要使用 lazy-init
注意:lazy延迟加载仅对singleton的scope有效,对于另外三种scope,默认就已经是lazy-init。
延迟加载Lazy-init (该值默认为false; 设置为true则会开启延迟加载)
XML中
<bean id="xxoo" class="com.freeknight.demo.xxoo" lazy-init=“true”> </bean>
- JAVA自动装配中
@Component @Lazy public class MyClass{ }
- JAVA手动装配中
@Configration public class AppConfig{ @Bean @Lazy public MyClass getMyClass(){ return new MyClass(); } }
Bean对象的初始化和销毁函数
当spring进行bean对象创建和销毁时,希望自动调用我们的初始化和释放函数.
假设有一个JAVA类
public class MyClass{ public void myInit(){ } public void myDestory(){ } }
使用时
XML中
<bean id="xxoo" class="com.freeknight.demo.xxoo" destory-method="myDestory" init-method="myInit"> </bean>
- JAVA自动装配中
@Component public class MyClass{ @PostConstruct public void myInit(){ } @PreDestory public void myDestory(){ } }
工厂方法创建bean对象
静态工厂方法 和 实例工厂方法
假设我们有一个类
public class Person{} public class PersonFactory{ public static Person createPersonS(){ return new Person(); } public Person createPersonI(){ return new Person(); } }
使用时
XML中
<!-- 静态工厂 --> <bean id="Person1" class="com.freeknight.demo.PersonFactory" factory-method="createPersonS"> </bean> <!-- 实例工厂 --> <bean id="PersonFactory" class="com.freeknight.demo.PersonFactory" /> <bean id="Person2" factory-bean="PersonFactory" factory-method="createPersonI"/>
其他扩展
log4j 添加pom的dependence,修改log4j.properties
junit 添加pom的dependence,在test目录下创建同名包,添加 @Test 函数测试
spring-test 添加pom的dependence,在test目录下创建同名包,添加 @RunWith(SpringJUnit4ClassRunner.class),加载配置类 @ContextConfiguration(classes=AppConfig.class)
spring, spring MVC, spring boot, spring cloud关系和区别
- spring
- 是一个大框架,包括众多衍生品,包括 spring boot, spring mvc, security, jpa等。但都基于IOC和AOP。
- IOC提供依赖注入的容器,AOP解决面向切面的编程。
- spring MVC
- 是一个基于servlet的MVC框架,用来处理web开发的路径映射和视图渲染,解决WEB开发问题。
- 它是spring框架里,关于web层开发的一部分
- 一般网页服务开发,会分为三层。WEB层 -> service层 -> dao层 -> 数据库
- 它和struts1, struts2平级,同样功能。
spring boot
- 为了简化spring开发者的使用,而出来的一套快速开发整合包。它增加了约定大于配置理念,快速集成多个 spring插件。
- 约定大于配置 :就是说如果没有做配置,就会使用默认配置,只有不符合默认值的配置,才需要额外配置。目的是让开发者减少复杂配置。
- 它专注于开发微服务后台接口,不负责前端视图的开发。
spring cloud
- 基于 spring boot 开发实现的一套云应用开发工具,它依赖于spring boot。
- spring boot更关注于单一微服务开发,但spring cloud更关注于将spring boot开发的微服务进行整合和管理,它包括服务发现注册,配置中心,消息总线,负载均衡,断路器,数据监控,一键启动部署等功能。
spring boot基本概念
特点
- 和spring一起诞生的微框架,上手简单,配置依赖少(不用xml)
- 可以不依赖容器(war包),直接独立运行
- 可以可视化监控和性能检查等
- 支持一个简单的 starter 依赖项,直接懒人包全部配置好(会略有依赖库的冗余)
用途
- 一般用在web项目中
- 一般用在微服务开发
入门流程
通过 https://start.spring.io/ 搭建框架,或者使用itellijIdea的spring initializer
编写代码
// demo1application.java @SpringBootApplication public class Demo1Application { public static void main(String[] args) { SpringApplication.run(Demo1Application.class, args); } }
// 一个简单的controller @RestController public class HelloController { @RequestMapping("/hello") String index() { return "Hello Spring Boot"; } }
- 运行 demo1application.java,本地访问 localhost:8080/hello 进行API测试
吐槽
这一切完全就是新瓶装老酒,我发现现在的技术 都特喜欢起新名词。
- 为了解耦,把反射机制做了个规范化,使用注释和XML配置方法实现,这就是IOC,DI。
- 啥TMD“约定大于配置”啊,任何一个ini config类,都有defaultvalue好吗?
- 我一直讨厌小语法糖,看起来的确似乎可以省点事,但最终你都要去了解去本质,逃不掉的。但记住大量语法糖的规则,还需要浪费很多注意力。spring里面就大量的语法糖,恶心。
- Bean的管理看起来很甜,问题是下面如何的对象管理都交给了别人,真的好不放心。原本java只是管理内存,现在都开始做对象管理了,很好。
- 简直是标注狂+配置狂,下一步应该是自动化代码生成工具吧?类似unreal的blueprint?
- 真能分层啊,view facade service dao mapper简直让人应接不暇,满地图的设计模式。