SSM学习之Spring

SSM-Spring框架学习

一、概念

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器(框架)。

二、优点

1、Spring是一个开源免费的框架 , 容器 .

2、Spring是一个轻量级的框架 , 非侵入式的 .

3、控制反转 IoC , 面向切面 Aop

4、对事物的支持 , 对框架的支持

三、组成

3.1 Spring 框架是一个分层架构

由 7 个定义良好的模块组成,Spring 模块构建在核心容器之上,核心容器定义了创建、配置和管理 bean 的方式 .

图片

3.2 组成 Spring 框架的每个模块(或组件)都可以单独存在:

  • 核心容器:核心容器提供 Spring 框架的基本功能。核心容器的主要组件是 BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC) 模式将应用程序的配置和依赖性规范与实际的应用程序代码分开。

  • Spring 上下文:Spring 上下文是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。

  • Spring AOP:通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能 , 集成到了 Spring 框架中。所以,可以很容易地使 Spring 框架管理任何支持 AOP的对象。Spring AOP 模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,不用依赖组件,就可以将声明性事务管理集成到应用程序中。

  • Spring DAO:JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。

  • Spring ORM:Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括 JDO、Hibernate 和 iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。

  • Spring Web 模块:Web 上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以,Spring 框架支持与 Jakarta Struts 的集成。Web 模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。

  • Spring MVC 框架:MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。

图片

拓展

Spring Boot与Spring Cloud

  • Spring Boot 是 Spring 的一套快速配置脚手架,可以基于Spring Boot 快速开发单个微服务;

  • Spring Cloud是基于Spring Boot实现的;

  • Spring Boot专注于快速、方便集成的单个微服务个体,Spring Cloud关注全局的服务治理框架;

  • Spring Boot使用了约束优于配置的理念,很多集成方案已经帮你选择好了,能不配置就不配置 , Spring Cloud很大的一部分是基于Spring Boot来实现,Spring Boot可以离开Spring Cloud独立使用开发项目,但是Spring Cloud离不开Spring Boot,属于依赖的关系。

  • SpringBoot在SpringClound中起到了承上启下的作用,如果你要学习SpringCloud必须要学习SpringBoot。

四、控制反转(IOC)

4.1 本质

  • 控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法

  • 控制反转是一种通过描述(XML或注解)并通过第三方去生产或获取特定对象的方式。在Spring中实现控制反转的是IoC容器,其实现方法是依赖注入(Dependency Injection,DI)

  • IoC是Spring框架的核心内容

    Spring容器在初始化时先读取配置文件,根据配置文件或元数据创建与组织对象存入容器中,程序使用时再从Ioc容器中取出需要的对象。<在配置文件加载的时候,容器中管理的对象就已经初始化了>

    图片

采用XML方式配置Bean的时候,Bean的定义信息是和实现分离的,而采用注解的方式可以把两者合为一体,Bean的定义信息直接以注解的形式定义在实现类中,从而达到了零配置的目的。

五、快速上手Spring

5.1 配置环境

导入Jar包

注 : spring 需要导入commons-logging进行日志记录 . 我们利用maven , 他会自动下载对应的依赖项 (包含测试依赖).


 
 org.springframework
 spring-webmvc
 5.2.0.RELEASE
 
 
 junit
 junit
 4.12
 test
 

5.2 编写代码

1、编写一个Hello实体类

public class Hello {
 private String name;

 public String getName() {
 return name;
 }
 public void setName(String name) {
 this.name = name;
 }

 public void show(){
 System.out.println("Hello,"+ name );
 }
}

2、编写我们的spring文件 , 这里我们命名为beans.xml


 
 
 
 

3、我们可以去进行测试了 .

@Test
public void test(){
 //解析beans.xml文件 , 生成管理相应的Bean对象
 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 //getBean : 参数即为spring配置文件中bean的id .
 Hello hello = (Hello) context.getBean("hello");
 hello.show();
}

思考

  • Hello 对象是谁创建的 ? 【hello 对象是由Spring创建的

  • Hello 对象的属性是怎么设置的 ? hello 对象的属性是由Spring容器设置的

这个过程就叫控制反转 :

  • 控制 : 谁来控制对象的创建 , 传统应用程序的对象是由程序本身控制创建的 , 使用Spring后 , 对象是由Spring来创建的

  • 反转 : 程序本身不创建对象 , 而变成被动的接收对象 .

依赖注入 : 就是利用set方法来进行注入的.

IOC是一种编程思想,由主动的编程变成被动的接收

可以通过newClassPathXmlApplicationContext去浏览一下底层源码 .

5.3 IOC创建对象方式

5.3.1 通过无参构造方法来创建

1、User.java

public class User {

 private String name;

 public User() {
 System.out.println("user无参构造方法");
 }

 public void setName(String name) {
 this.name = name;
 }

 public void show(){
 System.out.println("name="+ name );
 }

}

2、beans.xml




 
 
 


3、测试类

@Test
public void test(){
 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 //在执行getBean的时候, user已经创建好了 , 通过无参构造
 User user = (User) context.getBean("user");
 //调用对象的方法 .
 user.show();
}

结果可以发现,在调用show方法之前,User对象已经通过无参构造初始化了!

5.3.2 通过有参构造方法来创建

1、UserT . java

public class UserT {

 private String name;

 public UserT(String name) {
 this.name = name;
 }

 public void setName(String name) {
 this.name = name;
 }

 public void show(){
 System.out.println("name="+ name );
 }

}

2、beans.xml 有三种方式编写



   
   



   
   



   

3、测试

@Test
public void testT(){
 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 UserT user = (UserT) context.getBean("userT");
 user.show();
}

结论:在配置文件加载的时候。其中管理的对象都已经初始化了!

六、Spring配置

6.1 别名

alias 设置别名 , 为bean设置别名 , 可以设置多个别名



6.2 Bean的配置





 

6.3 import

团队的合作通过import来实现 .

七、依赖注入(DI)

7.1 概念

  • 依赖注入(Dependency Injection,DI)。

  • 依赖 : 指Bean对象的创建依赖于容器 . Bean对象的依赖资源 .

  • 注入 : 指Bean对象所依赖的资源 , 由容器来设置和装配 .

7.2 Set注入

要求被注入的属性 , 必须有set方法 , set方法的方法名由set + 属性首字母大写 , 如果属性是boolean类型 , 没有set方法 , 是 is .

测试pojo类 :

Address.java

 public class Address {

     private String address;

     public String getAddress() {
         return address;
    }

     public void setAddress(String address) {
         this.address = address;
    }
 }

Student.java

package com.kuang.pojo;

 import java.util.List;
 import java.util.Map;
 import java.util.Properties;
 import java.util.Set;

 public class Student {

     private String name;
     private Address address;
     private String[] books;
     private List hobbys;
     private Map card;
     private Set games;
     private String wife;
     private Properties info;

     public void setName(String name) {
         this.name = name;
    }

     public void setAddress(Address address) {
         this.address = address;
    }

     public void setBooks(String[] books) {
         this.books = books;
    }

     public void setHobbys(List hobbys) {
         this.hobbys = hobbys;
    }

     public void setCard(Map card) {
         this.card = card;
    }

     public void setGames(Set games) {
         this.games = games;
    }

     public void setWife(String wife) {
         this.wife = wife;
    }

     public void setInfo(Properties info) {
         this.info = info;
    }

     public void show(){
         System.out.println("name="+ name
                 + ",address="+ address.getAddress()
                 + ",books="
        );
         for (String book:books){
             System.out.print("<<"+book+">>\t");
        }
         System.out.println("\n爱好:"+hobbys);

         System.out.println("card:"+card);

         System.out.println("games:"+games);

         System.out.println("wife:"+wife);

         System.out.println("info:"+info);

    }
 }

7.2.1 常量注入


     
 

测试:

@Test
 public void test01(){
     ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");

     Student student = (Student) context.getBean("student");

     System.out.println(student.getName());

 }

7.2.2 Bean注入

注意点:这里的值是一个引用,ref


     
 

 
     
     
 

7.2.3 数组注入

 
     
     
     
         
             西游记
             红楼梦
             水浒传
         
     
 

7.2.4 List注入

 
 
 听歌
 看电影
 爬山
 
 

7.2.5 Map注入


 
 
 
 
 

7.2.6 set注入

 
 
 LOL
 BOB
 COC
 
 

7.2.7 Null注入


7.2.8 Properties注入


 
 20190604
 
 小明
 
 

扩展:Properties和Map都是以键值对的形式存储的,但是他们有什么区别吗?

最大的区别就是 Properties可以直接导入IO流 读取IO流中的数据 并且能把自己的元素输出到IO流中。就是我们可以去写properties文件,进行读写。

7.3 p命名和c命名注入

7.3.1 P命名空间注入 : 需要在头文件中加入约束文件

导入约束 : xmlns:p="http://www.springframework.org/schema/p"

 
 

7.3.2 c 命名空间注入 : 需要在头文件中加入约束文件

导入约束 : xmlns:c="http://www.springframework.org/schema/c"
 
 

7.4 Bean的作用域

在Spring中,那些组成应用程序的主体及由Spring IoC容器所管理的对象,被称之为bean。简单地讲,bean就是由IoC容器初始化、装配及管理的对象 .

图片

7.4.1 Singleton

当一个bean的作用域为Singleton,那么Spring IoC容器中只会存在一个共享的bean实例,并且所有对bean的请求,只要id与该bean定义相匹配,则只会返回bean的同一实例。

7.4.2 Prototype

当一个bean的作用域为Prototype,表示一个bean定义对应多个对象实例。Prototype作用域的bean会导致在每次对该bean请求(将其注入到另一个bean中,或者以程序的方式调用容器的getBean()方法)时都会创建一个新的bean实例。Prototype是原型类型,它在我们创建容器的时候并没有实例化,而是当我们获取bean的时候才会去创建一个对象,而且我们每次获取到的对象都不是同一个对象。


 或者
 

对有状态的bean应该使用prototype作用域,而对无状态的bean则应该使用singleton作用域

补充:scope中单例(singleton)和prototype的优缺点:

singleton(默认):优点:不会new对象,节省资源;缺点:在处理高并发的时候可能会延迟或数据不一致 prototype:优点:多线程稳定 缺点:每次在创建浪费资源 多线程使用prototype,单线程使用singleton

7.4.3 Request

当一个bean的作用域为Request,表示在一次HTTP请求中,一个bean定义对应一个实例。即每个HTTP请求都会有各自的bean实例,它们依据某个bean定义创建而成。

针对每次HTTP请求,Spring容器会根据loginAction bean的定义创建一个全新的LoginAction bean实例,且该loginAction bean实例仅在当前HTTP request内有效。当处理请求结束,request作用域的bean实例将被销毁。


7.4.3 Session

当一个bean的作用域为Session,表示在一个HTTP Session中,一个bean定义对应一个实例。该作用域仅在基于web的Spring ApplicationContext情形下有效。


针对某个HTTP Session,Spring容器会根据userPreferences bean定义创建一个全新的userPreferences bean实例,且该userPreferences bean仅在当前HTTP Session内有效.

八、自动装配

8.1 概念

  • 自动装配是使用spring满足bean依赖的一种方法

  • spring会在应用上下文中为某个bean寻找其依赖的bean。

8.2 装配机制

Spring中bean有三种装配机制,分别是:

  1. 在xml中显式配置;

  2. 在java中显式配置;

  3. 隐式的bean发现机制和自动装配。

8.3 实现

Spring的自动装配需要从两个角度来实现,或者说是两个操作:

  1. 组件扫描(component scanning):spring会自动发现应用上下文中所创建的bean;

  2. 自动装配(autowiring):spring自动满足bean之间的依赖,也就是我们说的IoC/DI;

1、新建一个项目

2、新建两个实体类,Cat Dog 都有一个叫的方法

public class Cat {
 public void shout() {
 System.out.println("miao~");
 }
}
public class Dog {
 public void shout() {
 System.out.println("wang~");
 }
}

3、新建一个用户类 User

public class User {
 private Cat cat;
 private Dog dog;
 private String str;
}

4、编写Spring配置文件




 
 

 
 
 
 
 

5、测试

public class MyTest {
 @Test
 public void testMethodAutowire() {
 ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
 User user = (User) context.getBean("user");
 user.getCat().shout();
 user.getDog().shout();
 }
}

8.3.1 autowire byName (按名称自动装配)

由于在手动配置xml过程中,常常发生字母缺漏和大小写等错误,而无法对其进行检查,使得开发效率降低。

采用自动装配将避免这些错误,并且使配置简单化。

测试:

1、修改bean配置,增加一个属性 autowire="byName"


 

2、再次测试,结果依旧成功输出!

3、我们将 cat 的bean id修改为 catXXX

4、再次测试, 执行时报空指针java.lang.NullPointerException。因为按byName规则找不对应set方法,真正的setCat就没执行,对象就没有初始化,所以调用时就会报空指针错误。

小结:

当一个bean节点带有 autowire byName的属性时。

  1. 将查找其类中所有的set方法名,例如setCat,获得将set去掉并且首字母小写的字符串,即cat。

  2. 去spring容器中寻找是否有此字符串名称id的对象。

  3. 如果有,就取出注入;如果没有,就报空指针异常。

8.3.2 autowire byType (按类型自动装配)

使用autowire byType首先需要保证:同一类型的对象,在spring容器中唯一。如果不唯一,会报不唯一的异常。NoUniqueBeanDefinitionException

测试:

1、将user的bean配置修改一下 : autowire="byType"

2、测试,正常输出

3、在注册一个cat 的bean对象!






 

4、测试,报错:NoUniqueBeanDefinitionException

5、删掉cat2,将cat的bean名称改掉!测试!因为是按类型装配,所以并不会报异常,也不影响最后的结果。甚至将id属性去掉,也不影响结果。

九、使用注解

9.1 配置

jdk1.5开始支持注解,spring2.5开始全面支持注解。

准备工作:利用注解的方式注入属性。

1、在spring配置文件中引入context文件头

xmlns:context="http://www.springframework.org/schema/context"

http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd

2、开启属性注解支持!

9.2 @Autowired

  • @Autowired是按类型自动转配的,不支持id匹配。

  • 需要导入 spring-aop的包!

测试:

1、将User类中的set方法去掉,使用@Autowired注解

public class User {
   @Autowired
   private Cat cat;
   @Autowired
   private Dog dog;
   private String str;

   public Cat getCat() {
       return cat;
  }
   public Dog getDog() {
       return dog;
  }
   public String getStr() {
       return str;
  }
}

2、此时配置文件内容






3、测试,成功输出结果!

【补充】

@Autowired(required=false) 说明:false,对象可以为null;true,对象必须存对象,不能为null。

//如果允许对象为null,设置required = false,默认为true
@Autowired(required = false)
private Cat cat;

9.3 @Qualifier

  • @Autowired是根据类型自动装配的,加上@Qualifier则可以根据byName的方式自动装配

  • @Qualifier不能单独使用。

测试实验步骤:

1、配置文件修改内容,保证类型存在对象。且名字不为类的默认名字!





2、没有加Qualifier测试,直接报错

3、在属性上添加Qualifier注解

@Autowired
@Qualifier(value = "cat2")
private Cat cat;
@Autowired
@Qualifier(value = "dog2")
private Dog dog;

测试,成功输出!

9.4 @Resource

  • @Resource如有指定的name属性,先按该属性进行byName方式查找装配;

  • 其次再进行默认的byName方式进行装配;

  • 如果以上都不成功,则按byType的方式自动装配。

  • 都不成功,则报异常。

实体类:

public class User {
   //如果允许对象为null,设置required = false,默认为true
   @Resource(name = "cat2")
   private Cat cat;
   @Resource
   private Dog dog;
   private String str;
}

beans.xml






测试:结果OK

配置文件2:beans.xml , 删掉cat2



实体类上只保留注解

@Resource
private Cat cat;
@Resource
private Dog dog;

结果:OK

结论:先进行byName查找,失败;再进行byType查找,成功。

9.5 @Nullable <补充>

字段标记了这个注解,说明这个字段可以为null

小结

@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。

十、使用注解开发

10.1 配置

在spring4之后,想要使用注解形式,必须得要引入aop的包

图片

在配置文件当中,还得要引入一个context约束




10.2 bean的实现

1、配置扫描哪些包下的注解



2、在指定包下编写类,增加注解

@Component("user")
// 相当于配置文件中 
public class User {
   public String name = "alen";
}

3、测试

@Test
public void test(){
   ApplicationContext applicationContext =
       new ClassPathXmlApplicationContext("beans.xml");
   User user = (User) applicationContext.getBean("user");
   System.out.println(user.name);
}

10.3 属性注入

使用注解注入属性

1、可以不用提供set方法,直接在直接名上添加@value("值")

@Component("user")
// 相当于配置文件中 
public class User {
   @Value("alen")
   // 相当于配置文件中 
   public String name;
}

2、如果提供了set方法,在set方法上添加@value("值");

@Component("user")
public class User {

   public String name;

   @Value("alen")
   public void setName(String name) {
       this.name = name;
  }
}

10.4 衍生注解

@Component三个衍生注解

为了更好的进行分层,Spring可以使用其它三个注解,功能一样,目前使用哪一个功能都一样。

  • @Controller:web层

  • @Service:service层

  • @Repository:dao层

写上这些注解,就相当于将这个类交给Spring管理装配了!

10.5 作用域

@scope

  • singleton:默认的,Spring会采用单例模式创建这个对象。关闭工厂 ,所有的对象都会销毁。

  • prototype:多例模式。关闭工厂 ,所有的对象不会销毁。内部的垃圾回收机制会回收

@Controller("user")
@Scope("prototype")
public class User {
   @Value("alen")
   public String name;
}

小结:

XML与注解比较

  • XML可以适用任何场景 ,结构清晰,维护方便

  • 注解不是自己提供的类使用不了,开发简单方便

xml与注解整合开发 :推荐最佳实践

  • xml管理Bean

  • 注解完成属性注入

  • 使用过程中, 可以不用扫描,扫描是为了类上的注解

作用:

  • 进行注解驱动注册,从而使注解生效

  • 用于激活那些已经在spring容器里注册过的bean上面的注解,也就是显示的向Spring注册

  • 如果不扫描包,就需要手动配置bean

  • 如果不加注解驱动,则注入的值为null!

10.6 基于Java类进行配置

JavaConfig 原来是 Spring 的一个子项目,它通过 Java 类的方式提供 Bean 的定义信息,在 Spring4 的版本, JavaConfig 已正式成为 Spring4 的核心功能 。

测试:

1、编写一个实体类,Dog

@Component  //将这个类标注为Spring的一个组件,放到容器中!
public class Dog {
   public String name = "dog";
}

2、新建一个config配置包,编写一个MyConfig配置类

@Configuration  //代表这是一个配置类
public class MyConfig {

   @Bean //通过方法注册一个bean,这里的返回值就Bean的类型,方法名就是bean的id!
   public Dog dog(){
       return new Dog();
  }

}

3、测试

@Test
public void test2(){
   ApplicationContext applicationContext =
           new AnnotationConfigApplicationContext(MyConfig.class);
   Dog dog = (Dog) applicationContext.getBean("dog");
   System.out.println(dog.name);
}

导入其他配置如何做呢?

1、我们再编写一个配置类!

@Configuration  //代表这是一个配置类
public class MyConfig2 {
}

2、在之前的配置类中我们来选择导入这个配置类

@Configuration
@Import(MyConfig2.class)  //导入合并其他配置类,类似于配置文件中的 inculde 标签
public class MyConfig {

   @Bean
   public Dog dog(){
       return new Dog();
  }

}

你可能感兴趣的:(SSM学习之Spring)