# spring-learning
**Repository Path**: OwlIntheOaktree/spring-learning
## Basic Information
- **Project Name**: spring-learning
- **Description**: 在狂神说上看的教程,来建的spring演示和学习代码仓库
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2021-04-11
- **Last Updated**: 2021-04-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# Spring学习
## spring-01-ioc
dao层负责与数据库交互完成业务
service层负责与用户交互,并调用dao层的实现类来完成用户需要的业务
起先,需要增加业务不仅需要在dao层增加实现类,还需要修改service层实现类的源代码来改变调用的dao层实现类,
后来在service层的实现类中增加一个set方法,通过set方法来确定使用的dao层实现类(OOP设计原则中的组合的思想),这样就可以在用户调用时,通过用户根据需要的功能选择需要的dao层实现类来实现相应的业务,这就是控制反转(IOC)——将原来需要经程序员手实现的业务调用通过用户来实现
这是IOC的原型和基本思想。
**Spring IOC的本质**
**控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)。**
## Spring-03-di
### bean的创建方式
默认通过无参构造创建
如果显示定义了有参构造那么需要传入参数来进行创建
- 通过参数的 索引序号
```xml
```
- 通过参数的 类型
```xml
```
- 通过参数的 name 或者 通过ref指定其他bean
```xml
```
### c命名空间 p命名空间
需要在 beans标签中引入命名空间
```xml
xmlns:p="http://www.springframework.org/schema/p"
xmlns:c="http://www.springframework.org/schema/c"
```
```xml
```
### Bean的作用域
| Scope | Description |
| ------------------------------------------------------------ | ------------------------------------------------------------ |
| [singleton](https://docs.spring.io/spring-framework/docs/4.3.9.RELEASE/spring-framework-reference/html/beans.html#beans-factory-scopes-singleton) | (Default) Scopes a single bean definition to a single object instance per Spring IoC container. |
| [prototype](https://docs.spring.io/spring-framework/docs/4.3.9.RELEASE/spring-framework-reference/html/beans.html#beans-factory-scopes-prototype) | Scopes a single bean definition to any number of object instances. |
| [request](https://docs.spring.io/spring-framework/docs/4.3.9.RELEASE/spring-framework-reference/html/beans.html#beans-factory-scopes-request) | Scopes a single bean definition to the lifecycle of a single HTTP request; that is, each HTTP request has its own instance of a bean created off the back of a single bean definition. Only valid in the context of a web-aware Spring `ApplicationContext`. |
| [session](https://docs.spring.io/spring-framework/docs/4.3.9.RELEASE/spring-framework-reference/html/beans.html#beans-factory-scopes-session) | Scopes a single bean definition to the lifecycle of an HTTP `Session`. Only valid in the context of a web-aware Spring `ApplicationContext`. |
| [globalSession](https://docs.spring.io/spring-framework/docs/4.3.9.RELEASE/spring-framework-reference/html/beans.html#beans-factory-scopes-global-session) | Scopes a single bean definition to the lifecycle of a global HTTP `Session`. Typically only valid when used in a Portlet context. Only valid in the context of a web-aware Spring `ApplicationContext`. |
| [application](https://docs.spring.io/spring-framework/docs/4.3.9.RELEASE/spring-framework-reference/html/beans.html#beans-factory-scopes-application) | Scopes a single bean definition to the lifecycle of a `ServletContext`. Only valid in the context of a web-aware Spring `ApplicationContext`. |
| [websocket](https://docs.spring.io/spring-framework/docs/4.3.9.RELEASE/spring-framework-reference/html/websocket.html#websocket-stomp-websocket-scope) | Scopes a single bean definition to the lifecycle of a `WebSocket`. Only valid in the context of a web-aware Spring `ApplicationContext`. |
## spring-04-autowriting
1. **xml的方式** 注册好属性相关的bean后再注册复杂对象,直接使用 autowire="byName" 或者 autowire="byType"
```xml
```
2. **通过注解**
> 需要导入 约束
>
> 在beans标签中添加
>
> ```xml
> xmlns:context="
> http://www.springframework.org/schema/context
> https://www.springframework.org/schema/context/spring-context.xsd"
> ```
@Autowrited
或者 @Autowrited + @Qualifier(value = "beanName")
或者@Resource
**小结**
@Autowired与@Resource异同:
1、@Autowired与@Resource都可以用来装配bean。都可以写在字段上,或写在setter方法上。
2、@Autowired默认按类型装配(属于spring规范),默认情况下必须要求依赖对象必须存在,如果要允许null 值,可以设置它的required属性为false,如:@Autowired(required=false) ,如果我们想使用名称装配可以结合@Qualifier注解进行使用
3、@Resource(属于J2EE复返),默认按照名称进行装配,名称可以通过name属性进行指定。如果没有指定name属性,当注解写在字段上时,默认取字段名进行按照名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
它们的作用相同都是用注解方式注入对象,但执行顺序不同。@Autowired先byType,@Resource先byName。
## spring-05-annotation
> 说明
在spring4之后,想要使用注解形式,必须得要引入aop的包
```xml
org.springframework
spring-aop
5.2.13.RELEASE
```
在配置文件当中,还得要引入一个context约束
```xml
```
> Bean的实现
我们之前都是使用 bean 的标签进行bean注入,但是实际开发中,我们一般都会使用注解!
1、配置扫描哪些包下的注解
```
```
2、在指定包下编写类,增加注解
```java
@Component("user")
// 相当于配置文件中
```
> 属性注入
使用注解注入属性
1、可以不用提供set方法,直接在直接名上添加@value("值")
2、如果提供了set方法,在set方法上添加@value("值");
> 衍生注解
我们这些注解,就是替代了在配置文件当中配置步骤而已!更加的方便快捷!
**@Component三个衍生注解**
为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。
- @Controller:web层
- @Service:service层
- @Repository:dao层
写上这些注解,就相当于将这个类交给Spring管理装配了!
> 自动装配注解
在Bean的自动装配已经讲过了,可以回顾!
> 作用域
@scope
- singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。
- prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收
> 小结
**XML与注解比较**
- XML可以适用任何场景 ,结构清晰,维护方便
- 注解不是自己提供的类使用不了,开发简单方便
**xml与注解整合开发** :推荐最佳实践
- xml管理Bean
- 注解完成属性注入(**@Autowrited**)
- 使用过程中, 可以不用扫描,扫描是为了类上的注解
```
```
作用:
- 进行注解驱动注册,从而使注解生效
- 用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显示的向Spring注册
- 如果不扫描包,就需要手动配置bean
- 如果不加注解驱动,则注入的值为null!
## spring-06-myconfig
> 基于Java类进行配置
JavaConfig 原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的版本, JavaConfig 已正式成为 Spring4 的核心功能 。
测试:
1、编写一个实体类,Dog
```java
@Component //将这个类标注为Spring的一个组件,放到容器中!
public class Dog {
public String name = "dog";
}
```
2、新建一个config配置包,编写一个MyConfig配置类
```java
@Configuration //代表这是一个配置类
public class MyConfig {
@Bean //通过方法注册一个bean,这里的返回值就Bean的类型,方法名就是bean的id!
public Dog dog(){
return new Dog();
}
}
```
3、测试
```java
@Test
public void test2(){
ApplicationContext applicationContext =
new AnnotationConfigApplicationContext(MyConfig.class);
Dog dog = (Dog) applicationContext.getBean("dog");
System.out.println(dog.name);
}
```
4、成功输出结果!
**导入其他配置如何做呢?**
1、我们再编写一个配置类!
```java
@Configuration //代表这是一个配置类
public class MyConfig2 {
}
```
2、在之前的配置类中我们来选择导入这个配置类
```java
@Configuration
@Import(MyConfig2.class) //导入合并其他配置类,类似于配置文件中的 inculde 标签
public class MyConfig {
@Bean
public Dog dog(){
return new Dog();
}
}
```
关于这种Java类的配置方式,我们在之后的SpringBoot 和 SpringCloud中还会大量看到,我们需要知道这些注解的作用即可!
## 知识回顾1
Spring的使用步骤
- 1 所有类都要注册到bean里面 xml的方式,注解的方式……
- 2 所有的bean都需要通过容器去取 context.getBean("XXX") (**newClassPathXmlApplicationContext("applicationContext.xml")** 或者 **AnnotationConfigApplicationContext(MyConfig.class)**)
- 3 从容器中取出的bean就是一个对象,拿出来即可调用
思考问题?
- Hello对象是谁创建的?
hello 对象是由Spring创建的
- Hello 对象的属性是怎么设置的?
hello对象的属性是由Spring容器设置的 ——DI 依赖注入
- 这个讨程就叫控制反转:
- 控制:谁来控制对象的创建,传统应用程序的对象是由程序本身控制创建的,使用Spring后,对象是由Spring来创建的。
- 反转:程序本身不创建对象,而变成被动的接收对象
依赖注入:就是利用set方法来进行注入的
**IOC是一种编程思想,由主动的编程变成被动的接收**
可以通过**newClassPathXmlApplicationContext**去浏览一下底层源码
OK,到了现在,我们彻底不用再程序中去改动了,要实现不同的操作,只需要在xml配置文件中进行修改,
**所谓的 loC,一句话搞定:对象由Spring来创建,管理,装配!**
## spring-07-aop
代理模式是SpringAop的底层
### 静态代理
代理模式 真实的人(房东) 真实的业务(租房子) 代理(中介) 客人找中介而不是直接找房东!
**静态代理的好处:**
- 可以使得我们的真实角色更加纯粹 . 不再去关注一些公共的事情 .
- **公共的业务由代理来完成** . 实现了业务的分工 ,
- **公共业务发生扩展时变得更加集中和方便 **.
缺点 :
- 类多了 , 多了代理类 , 工作量变大了 . 开发效率降低 .
我们想要静态代理的好处,又不想要静态代理的缺点,所以 , 就有了动态代理 !
**我们在不改变原来的代码的情况下,实现了对原有功能的增强,这是AOP中最核心的思想**
#### 业务的开发
纵向开发
横向开发——AOP去实现

### 动态代理
- 动态代理的角色和静态代理的一样 .
- 动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的
- 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理
- - 基于接口的动态代理----JDK动态代理
- 基于类的动态代理--cglib
- 现在用的比较多的是 javasist 来生成动态代理 . 百度一下javasist
- 我们这里使用JDK的原生代码来实现,其余的道理都是一样的!、
**JDK的动态代理需要了解两个类**
核心 : InvocationHandler 和 Proxy , 打开JDK帮助文档看看
【InvocationHandler:调用处理程序】——实现 invoke方法来完成处理业务
【Proxy : 代理】—— 一个类,使用它的静态方法
**动态代理的本质就是使用反射!**
```java
public class ProxyInvocationHandler implements InvocationHandler {
private Object target; // 需要代理的目标类
public void setTarget(Object target) {
this.target = target;
}
// 生成代理的类
public Object getProxy(){
return Proxy.newProxyInstance(
this.getClass().getClassLoader(),
target.getClass().getInterfaces(),
this);
}
// proxy——代理类
// method —— 代理类需要调用的处理方法对象
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
log(method.getName());
return method.invoke(target,args);
}
// 需要自己定义的一些业务代码
public void log(String methodName){
System.out.println("执行了" + methodName +"方法");
}
}
```