Spring核心知识(一)

简介: Spring是一个JavaEE开源的轻量级别的框架,可以解决我们企业开发中遇到的难题,能够让编码变的更加简单,核心组件IOC容器和Aop面向切面编程。

简介

       Spring是一个JavaEE开源的轻量级别的框架,可以解决我们企业开发中遇到的难题,能够让编码变的更加简单,核心组件IOC容器和Aop面向切面编程。

spring优点:

  • 方便解耦,简化开发
  • 管理对象
  • 集成其他框架
  • Junit单元测试
  • 方便进行事务操作
  • 降低API开发难度

Spring核心特性:

依赖注入 (DI):

Inversion of Control (IoC) 控制反转是一个通用概念,可以用多种不同的方式表达。 依赖注入只是控制反转的一个具体例子。在编写复杂的 Java 应用程序时,应用程序类应尽可能独立于其他 Java 类,以增加重用这些类的可能性,并在单元测试时独立于其他类对其进行测试。 依赖注入有助于将这些类粘合在一起,同时保持它们的独立性。

依赖注入简单来说,例如,依赖,A 类依赖于B类。注入就意味着,B 类将被 IoC 注入到 A 类中。


面向切面编程(AOP)

跨越应用程序多个点的功能称为横切关注点,这些横切关注点在概念上与应用程序的业务逻辑分开。 有各种常见的好例子,包括日志记录、声明式事务、安全性、缓存等。

OOP 中模块化的关键单元是类,而 AOP 中模块化的单元是方面。 DI 可帮助您将应用程序对象彼此分离,而 AOP 可帮助您将横切关注点与它们影响的对象分离。

面向切面是一种思想,不是具体的框架,也不是具体的代码。

Spring体系结构图:

spring的官网:

https://spring.io/

Spring官方下载依赖jar包地址:

https://repo.spring.io/webapp/#/artifacts/browse/tree/General/libs-release-local/org/springframework/spring


Spring核心知识点

SpringIOC

IOC(Inversion of Control) 控制反转是一种面对对象编程的设计原则,用于降低代码之间的耦合度。IOC容器主要作用就是创建对象和处理对象之间的依赖关系。

Bean的管理

  • 使用spring创建对象
  • 使用spring注入属性

创建对象

  1. 单独new方式---耦合度太高

每次单独new对象,没有实现统一管理对象,如果后期userDao的名称信息发生变化的情况下,需要改变的引用地方比较多,耦合度太高。

  1. 工厂模式---降低我们耦合度

概念:统一的管理和维护我们每个对象创建与使用的过程。

不需要自己new对象。

  1. 反射的方式

降低代码的-耦合度

反射创建对象

方法一:调用无参数构造器创建对象
  • 利用无参构造器
  • 给类添加一个无参构造器(缺省构造器)
  • 配置bean元素
  • 调用容器的getbean
public class  Fast {
    public Fast() {
  System.out.println("spring创建对象方式一:通过无参构造方法");
 }
}


<!--
    使用无参构造器创建对象
    id属性:bean的名称,要求唯一
    class属性:类的全名
    -->
    <bean id="Fast" class="Fast"></bean>
@Test
public void test01(){
   ApplicationContext applicationContext=
       new ClassPathXmlApplicationContext("bean.xml");
}

输出:

方法二:调用有参构造方法来创建对象
public class Slow {
    private Integer id;
    private String name;
    public Slow(Integer id,String name){
        //super();
        this.id = id;
        this.name = name;
        System.out.println("spring创建对象方式2:通过有参构造方法"+"\n"+id+"-"+name);
    }
}
<bean id="slow" class="Slow">
        <!--
          constructor-arg:是有参构造方法的使用标签
          index:参数的索引,从 0 开始
          name: 参数名
          type:参数类型(区分开关键字和封装类 int 和 Integer)
          此时的创建对象相当于:SomeBean2 bean=new SomeBean2(1,"alice");
           -->
        <constructor-arg index="0" name="id" type="java.lang.Integer" value="1"/>
        <constructor-arg index="1" name="name" type="java.lang.String" value="alice"/>
    </bean>
@Test
public void test01(){
   ApplicationContext applicationContext=
       new ClassPathXmlApplicationContext("bean.xml");
}

输出:

方法三:使用静态工厂方法创建对象

通过调用类的静态工厂方法来创建对象

public class  Fast {
    public Fast() {
        System.out.println("spring创建对象第3种方式:通过静态方法工厂创建");
    }
}


public class FastFactory {
    public static Fast getInstance(){
        System.out.println("通过静态方法工厂创建对象");
        return new Fast();
      //相当于Fast.getInstance();
    }
}
<!--
    使用静态工厂方法创建对象
    factory-method属性:指定一个静态方法,spring容器会调用这个静态方法来创建对象
    -->
    <bean id="FastFactory"
          class="FastFactory"
          factory-method="getInstance"></bean>
@Test
public void test01(){
   ApplicationContext applicationContext=
       new ClassPathXmlApplicationContext("bean.xml");
}

输出:

方法四:使用实例工厂方法来创建对象

调用对象的实例方法来创建对象

public class cost {
    public cost(){
        System.out.println("通过实例工厂创建对象");
    }
}
public class costFactory {
    public cost getInstance(){
        return new cost();
    }
}
<!--通过实例工厂创建对象
     使用实例工厂方法来创建对象
   factory-bean属性:指定一个bean的ID,
   factory-method属性:指定一个方法
   spring容器会调用这个bean的对应的方法来创建对象。
    costFactory factory=new costFactory();
    cost cost=factory.getInstance();-->
    <bean id="factory" class="costFactory"></bean>
    <bean id="cost" factory-bean="factory" factory-method="getInstance"></bean>
@Test
public void test01(){
   ApplicationContext applicationContext=
       new ClassPathXmlApplicationContext("bean.xml");
}

输出:

方法五:使用实例工厂创建对象
public class messageBean {
    public messageBean(){
        System.out.println("通过实现FactoryBean接口实现对象的创建");
    }
}
public class bean implements FactoryBean<messageBean> {
    @Override
    public messageBean getObject() throws Exception {
        return null;
    }
    @Override
    public Class<?> getObjectType() {
        return null;
    }
    @Override
    public boolean isSingleton() {
        return true;
    }
}
<!--通过factorybean 来创建对象-->
    <bean id="factotybean" class="bean"></bean>
@Test
    public void test01(){
        ApplicationContext applicationContext=
                new ClassPathXmlApplicationContext("applicationContext.xml");
        messageBean bean=applicationContext.getBean("factotybean", messageBean.class);
    }

输出:

DI依赖注入

spring容器通过调用对象提供的set方法或者构造器来建立依赖关系。

依赖关系的创建流程

spring 容器启动后读取配置文件

基于对象属性set方法进行注入

在Bean标签下 在定义一个属性<property>标签

  • property元素:表示使用set方法来注入依赖关系

属性值包含特殊符号

1 把<>进行转义 &lt; &gt;

2 把带特殊符号内容写到CDATA

<!--<property name="bookName" value="<<武汉>>"></property> -->
    <property name="bookName">
        <value><![CDATA[<<武汉>>]]></value>
    </property>
  • name属性:指定属性值
  • ref属性:指定属性值(是被注入的bean的ID)
<!--
    property元素:表示使用set方法来注入依赖关系
    name属性:指定属性值
    ref属性:指定属性值(是被注入的bean的ID)
  <!--null值-->
        <property name="address"><null/></property>
        <!--属性值包含特殊符号
           1 把<>进行转义 &lt; &gt;
      2 把带特殊符号内容写到CDATA -->
    <property name="address"><value><![CDATA[<<上海>>]]></value>
    </property>
    -->


//注入属性 外部bean
   <bean id="dc1" class="ioc.dc">
    <bean id="db1" class="ioc.db">
        <property name="di" ref="dc1"></property>
    </bean>
public class db {
    private IB di;
  private String name;
    public void setName(String name) {
        this.name = name;
    }
    public void setDi(IB di) {
        this.di = di;
        System.out.println("调用了方法");
    }
}
public class di implements IB{
  private String diname;
    public di(){
    }
   public void setDiname(String diname) {
        this.diname = diname;
    }
    public void f1(){
        System.out.println("注入bean的属性");
    }
}
/*test01
    测试set方式的注入
    * */
    @Test
    public void test01(){
        db db=abstractApplicationContext.getBean("db1",ioc.db.class);
        logger.info("依赖注入成功。");
    }

输出:

注入属性---外部bean

//注入属性 外部bean
   <bean id="dc1" class="ioc.dc">
    <bean id="db1" class="ioc.db">
        <property name="di" ref="dc1"></property>
    </bean>

注入属性---内部bean

//注入属性---内部bean
<property name="name" value="mysql"></property>
        <property name="di" >
            <bean id="di2" class="ioc.di">
                <property name="diname" value="MYSQL AB"></property>
            </bean>
        </property>
    </bean>
利用构造器方式进行注入

在Bean标签下 在定义一个属性<constructor-arg >标签

constructor-arg 元素:构造器方式注入

name  指定参数列表名称index 指定参数列表索引,参数的下标(从0 开始)

public class A {
    private B b;
    public A(){
        System.out.println("A");
    }
    public A(B b){
        System.out.println("构造器方式注入");
        this.b=b;
    }
    public void execute(){
       System.out.println("成功注入");
       b.f1();
    }
}
public class B {
    public B(){
        System.out.println("对象被创建");
    }
    public void execute(){
        System.out.println("execute");
    }
    public void f1(){
        System.out.println("被成功注入");
    }
}
<!--
    constructor-arg 元素:构造器方式注入,其中,index 属性指定参数的下标(从0 开始)
    -->
    <bean id="b1" class="DI.B"></bean>
    <bean id="a1" class="DI.A">
        <constructor-arg index="0" ref="b1"></constructor-arg>
    </bean>
/*
    * 构造器注入
    * */
    @Test
    public void test01(){
        A a1=applicationContext.getBean("a1",A.class);
        a1.execute();
        logger.info("构造器方式注入完成");
    }



输出:

p名称空间注入

Xml头部引入P标签:

<?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:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans 
http://www.springframework.org/schema/beans/spring-beans.xsd">
</bean>
使用p标签注入属性:
<bean id="Book" class="book" p:bookName="books" p:bookPrice="66">
</bean>

p名称注入也是调用了set 方法注入属性。

集合类型属性注入

1. 注入数组类型

2. 注入list集合类型

3. 注入Map集合类型属性

4. 注入set集合属性

public class stu {
    //四种类型属性
    private String[] courses;
    private List<String> list;
    private Map<String,String> map;
    private Set<String> set;
    //学生所学多门课程
    private List<course> courseList;
    public void setCourseList(List<course> courseList) {
        this.courseList = courseList;
    }
    public String[] getCourses() {
        return courses;
    }
    public void setCourses(String[] courses) {
        this.courses = courses;
    }
    public List<String> getList() {
        return list;
    }
    public void setList(List<String> list) {
        this.list = list;
    }
    public Map<String, String> getMap() {
        return map;
    }
    public void setMap(Map<String, String> map) {
        this.map = map;
    }
    public Set<String> getSet() {
        return set;
    }
    public void setSet(Set<String> set) {
        this.set = set;
    }
}

 

<!--1 集合类型属性注入-->
    <bean id="stu" class="bean_stu.stu">
        <!--数组类型属性注入-->
        <property name="courses">
            <array>
                <value>体育</value>
                <value>数学</value>
            </array>
        </property>
        <!--list类型属性注入-->
        <property name="list">
            <list>
                <value>张三</value>
                <value>小三</value>
            </list>
        </property>
        <!--map类型属性注入-->
        <property name="map">
            <map>
                <entry key="soccer" value="足球"></entry>
                <entry key="basketball" value="篮球"></entry>
            </map>
        </property>
        <!--set类型属性注入-->
        <property name="set">
            <set>
                <value>SQL</value>
                <value>Java</value>
            </set>
        </property>


@Test
    public void test01(){
        AbstractApplicationContext abstractApplicationContext=new ClassPathXmlApplicationContext("bean2.xml");
         stu stu=abstractApplicationContext.getBean("stu", bean_stu.stu.class);
         String str= JSONObject.toJSONString(stu);
         logger.info(str);
    }

输出

集合里设置对象类型的值

<!--创建多个course对象-->
    <bean id="course1" class="bean_stu.course">
        <property name="cname" value="PHP"></property>
    </bean>
    <bean id="course2" class="bean_stu.course">
        <property name="cname" value="C++"></property>
    </bean>
        <!--注入list集合类型,值是对象-->
        <property name="courseList">
            <list>
                <ref bean="course1"></ref>
                <ref bean="course2"></ref>
            </list>
        </property>
    </bean>


util标签注入

util :命名空间,用以区分。

  • 先引入一个util名称空间,将集合类型的值配置成一个bean,借用引用的方式注入集合,set等
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
       xmlns:util="http://www.springframework.org/schema/util"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/util https://www.springframework.org/schema/util/spring-util.xsd">
<!--1 提取list集合类型属性注入-->
    <util:list id="bookList">
        <value>A</value>
        <value>B</value>
        <value>C</value>
    </util:list>
    <!--2 提取list集合类型属性注入使用  单例和多例-->
    <bean id="book" class="bean_stu.book" scope="prototype">
        <property name="list" ref="bookList"></property>
    </bean>
</beans>
  • 使用util标签读取properties 文件的内容

classpath:按照类的路径来搜索

spring 容器会依据路径来找对对应的properties文件,然后读取该文件的内容到properties

<util:properties id="config" location="classpath:config.properties"></util:properties>

  • 注入spring表达式
<bean id="sp1" class="res.SpelBean">
        <property name="name" value="#{vb1.name}"></property>
        <property name="age" value="#{vb1.age}"></property>
        <property name="city" value="#{vb1.city[1]}"></property>
        <property name="score"  value="#{vb1.score.english}"></property>
        <property name="pageSize" value="#{vb1.pageSize}"></property>
    </bean>

bean的常见属性

作用域

作用域

描述

singleton

在spring IoC容器仅存在一个Bean实例,Bean以单例方式存在,bean作用域范围的默认值。

prototype

每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时,相当于执行newXxxBean()。

request

每次HTTP请求都会创建一个新的Bean,该作用域仅适用于web的Spring WebApplicationContext环境。

session

同一个HTTP Session共享一个Bean,不同Session使用不同的Bean。该作用域仅适用于web的Spring WebApplicationContext环境。

application

限定一个Bean的作用域为ServletContext的生命周期。该作用域仅适用于web的Spring WebApplicationContext环境。

<!--scope 属性: 用来配置作用域,缺省值为 singleton(即一个bean只能创建一个实例)
      如果值为prototype(即一个bean会创建多个实例)-->
    <bean id="s2" class="cost" scope="prototype"></bean>
    <bean id="s4"  class="cost"  scope="singleton"></bean>
    <bean id="s5" class="cost" scope="session"></bean>
<!-- A bean definition with singleton scope -->
<bean id="..." class="..." scope="singleton">
<!-- collaborators and configuration for this bean go here -->
</bean>
生命周期

生命周期:初始化,分配资源 销毁 释放资源。

<!--生命周期:初始化,分配资源 销毁 释放资源。
    init-method属性:指定初始化方法:
    destroy-method属性:指定销毁方法 不过如果作用域为单例时,销毁方法才执行。
    lazy-init属性:指定是否延迟加载,如果为TRUE,表示延迟加载,容器不会直接创建bean实例。
    -->
    <bean id="messageBean1" class="init.messageBean" 
  init-method="init" destroy-method="destroy" lazy-init="true">
    </bean>
    <bean id="ExampleBean1" class="init.ExampleBean" 
  init-method="init" destroy-method="destroy" lazy-init="true"></bean>
自动装配

自动装配指的是spring容器依据某种规则,自动建立对象之间的依赖关系

(默认情况下,容器不会自动装配。)可以通过指定autowire属性来告诉容器进行自动装配(容器实际上还是通过调用set方法或者构造器来完成依赖关系的建立。)

  • autowire属性: 自动装配,属性有三个值
  • byName :容器依据属性名来查找对对应的bean,然后调用对应的set方法来完成注入。如果找不到对应的bean,注入为null。不可能找到多个符合条件。
  • byType:容器依据属性类型来查找对应的bean,然后调用对应的set方法来完成注入。如果找不到对应的bean,注入null,有可能找到多个符合条件的bean,此时会 出错。
  • constructor: 与byType类似,不同的是调用对应的构造器的来完成注入。
<bean id="wt" class="res.Waiter"></bean>
<bean id="res1" class="res.Restaurant" autowire="byType">
</bean>

SpringBean的注解形式

注解:注解是JDK5中推出的新特性,代码的特殊标记。

Bean的管理操作方式

1. 基于XML方式实现

2. 基于注解方式实现

注解可以使用在类、方法、属性上面。

使用注解的目的,简化xml的配置方式。

配置组件扫描

base-package属性:指定要扫描的包名,spring容器会扫描该包及其子包下面的所有的类,如果该类前面有特定的注解。

(比如@Component),则spring容器会将其纳入容器进行管理(相当于这儿配置了一个bean元素)

  通过注解来指定作用域

   <context:component-scan base-package="somebean"></context:component-scan>

自动扫描的注解标记

Spring提供的常用注解

  • @Component  将对象注入Spring容器中
  • @Service     注入业务逻辑对象
  • @Controller   控制器类
  • @Repository  注入dao对象

以上该四个注解底层都是基于@Component注解封装的,只是用于区分。

部分其他注解

@Autowired @Qualifier

  • 该注解支只持setter方式和构造器方式注解。当采用set方式注入时,可以将@Autowired添加到set方法前面,如果不使用@Qualifier,则容器会使用byType方式来注入,有可能出错。
  • 使用@Qualifier 明确要注入的对象类型id的bean的ID
  • 也可以直接将两个注解直接添加到属性前面,这样利用Java的反射机制,即使没有set方法,也可以。不过只会赋值,不会进行其他操作。
  • 当采用构造器注入时,可以将该注解添加到对应的构造器前面。
@Component("res")
public class res {
   /* @Autowired
    @Qualifier("wt3")*/
    private Waiter wt;
    public Waiter getWt() {
        return wt;
    }
@Autowired
    public void setWt(//注入进来的对象,类似于byName的属性。
            @Qualifier("wt3") Waiter wt) {
        this.wt = wt;
        System.out.println("测试:服务员");
    }
    public res(){
        System.out.println("res()");
    }
}


@Resource

只支持set方式注入

可以将该注解添加属性前,使用name属性指定要注入的bean的ID,(不指定会按照byType方式进行注入)

可以将该注解添加到属性前。

@Component("bar")
public class Bar {
    private Waiter wt;
    public Waiter getWt() {
        return wt;
    }
    @Resource(name = "wt3")
    public void setWt(Waiter wt) {
        this.wt = wt;
    }
    public Bar(){
        System.out.println("11");
    }
}

@Value注解

可以使用该注解来注入基本类型的值

也可以使用该注解来使用spring表达式

该注解可以添加到属性前,或者添加到对应的set方法前。

@Value("#{config.pagesize}")

   private String pageSize;

@Configuration 注解

作为配置类,替代 xml 配置文件

@Configuration //作为配置类,替代 xml 配置文件

@ComponentScan(basePackages = { "bean"})

public class SpringConfig {

}

注解实例

@Component("b1")
@Scope("singleton")//单例和多例
@Lazy(true)//延迟加载
public class bean {
   @Value("#{config.pagesize}")
    private String pageSize;
    @Value("alice")
    private String name;
    @PostConstruct
    //初始化方法
    public void init(){
        System.out.println("初始化");
    }
    @PreDestroy
   //销毁方法
    public void destroy(){
        System.out.println("销毁");
    }
    public bean(){
        System.out.println("bean()");
    }
   @Bean(name="Bean")
    public bean getBean(){
        bean bean = new bean();
        System.out.println("调用方法:"+bean);
        return bean;
    }
}
目录
相关文章
|
6月前
|
前端开发 Java 数据库连接
|
11月前
|
XML 设计模式 Java
Spring基础(上)
Spring基础(上)
|
11月前
|
XML Java 数据格式
Spring基础(下)
Spring基础(下)
|
Java 应用服务中间件 数据处理
Spring核心知识(五)
webflux是spring推出的响应式web框架,它的对标产品为spring-mvc, 与传统的spring-mvc相比较,webflux是完全非阻塞式的。
95 1
|
XML 缓存 安全
Spring核心知识(二)
AOP(Aspect Oriented Programming) 意为:面向切面编程,通过预编译方式和运行期间动态代理实现程序功能的统一维护的一种技术。利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合度降低,提高程序的可重用性,同时提高了开发的效率。 通俗表示:不通过修改源代码方式,在主干功能中添加新的功能。
53 1
|
Java Spring
Spring5 - 核心原理
Spring5 - 核心原理
66 0
BXA
|
消息中间件 缓存 NoSQL
深入理解Spring Boot核心原理
Spring Boot是一个用于构建基于Spring框架的独立应用程序的框架。它采用了自动配置的原则,以减少开发人员在搭建应用架构方面的时间和精力,同时提升了系统的可维护性和可扩展性
BXA
2819 0
|
缓存 监控 安全
Spring Boot框架基础介绍
Spring Boot 是一款基于 Spring 框架的开源应用程序开发工具,它旨在简化 Spring 应用程序的配置和开发过程。Spring Boot 提供了一种简单的方式来创建可独立运行的、生产级别的应用程序,并在需要时进行部署。Spring Boot 在微服务架构和云计算环境下得到了广泛应用,本文将介绍 Spring Boot 的特性、优势以及使用方法。
2288 0
|
开发框架 缓存 监控
Spring核心原理
Spring 是最受欢迎的企业级 Java 应用程序开发框架,数以百万的来自世界各地的开发人员使用 Spring 框架来创建性能好、易于测试、可重用的代码。
|
XML 缓存 Java
Spring系列二:基础篇(2)
​ 目录 IOC IOC 5.说一说什么是IOC?什么是DI? Java 是面向对象的编程语言,一个个实例对象相互合作组成了业务逻辑,原来,我们都是在代码里创建对象和对象的依赖。 所谓的IOC(控制反转):就是由容器来负责控制对象的生命周期和对象间的关系。以前是我们想要什么,就自己创建什么,现在是我们需要什么,容器就给我们送来什么。 引入IOC之前和引入IOC之后 也就是说,控制对象生命周期的不再是引用它的对象,而是容器。对具体对象,以前是它控制其它对象,现在所有对象都被容器控制,所以这就叫控制反转。 控制反转示意图 DI(依赖注入):指的是容器在实例化对象的时候把
104 0
Spring系列二:基础篇(2)