# 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去实现 ![图片](mdpic/业务的纵向开发与横向开发) ### 动态代理 - 动态代理的角色和静态代理的一样 . - 动态代理的代理类是动态生成的 . 静态代理的代理类是我们提前写好的 - 动态代理分为两类 : 一类是基于接口动态代理 , 一类是基于类的动态代理 - - 基于接口的动态代理----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 +"方法"); } } ```