Spring

  • Spring的概述
  • Spring的入门

什么是spring框架?

  • Spring是一个开源框架
  • Spring为简化企业级应用开发而生。使用Spring可以使简单的JavaBean实现以前只有EJB才能实现的功能
  • Spring使javaSE/JavaEE的一站式框架

Spring框架是由于软件开发的复杂性而创建的。Spring使用的是基本的JavaBean来完成以前只可能由EJB完成的事情。然而,Spring的用途不仅仅限于服务器端的开发。从简单性、可测试性和松耦合性角度而言,绝大部分Java应用都可以从Spring中受益。

◆目的:解决企业应用开发的复杂性

◆功能:使用基本的JavaBean代替EJB,并提供了更多的企业应用功能

◆范围:任何Java应用

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

Spring的优点

  • 方便解耦,简化开发
    • spring就是个大工厂,将所有对象创建和依赖关系维护,交给Spring管理
  • AOP编程的支持
    • Spring提供面向切面编程,可以方便的实现对程序进行权限拦截、运行监控等功能
  • 声明式事务的支持
    • 只需要通过配置就可以完成对事务的管理,而且无需手动编程
  • 方便程序测试
    • Spring对junit4支持,可以用过注解方便的测试Spring程序
  • 方便集成各种优秀框架
    • Spring不排斥各种优秀的开源框架,其内部提供了对各种优秀框架(如:Struts、Hibertnate、MyBatis等)的直接支持
  • 降低JavaEE API的使用难度
    • Spring对JavaEE开发中非常难用的一些API(JDBC、Javamail、远程调用等),都提供了封装,使这些API应用难度大大降低

Spring IOC的底层原理实现

传统方式的开发

UserService us=new UserService();

​ ↓ 面向接口编程

UserService us=new UserSerivceImpl();

​ ↓ ocp原则:open-close 原则,对程序拓展是open的,对修改程序代码是close

​ ↓ 尽量做到不修改程序的源码,实现对程序的扩展

​ 工厂模式

工厂类创建 示例对象

class FactoryBean{
    public static UserService getUs(){
        return new UserServiceImpl();
    }

}
UserService us=FactoryBean.getUs();

工厂+反射+配置文件

<bean id="us" class="com.imooc.UserServiceImpl"/>
class FactoryBean{
    public static Object getBean(String id){
        ...
        反射
    }
}

Spring IOC的快速入门案例

  1. 创建Maven工程

    pom.xml

    spring相关依赖

    spring-core/spring-context/spring-beans/spring-logging

    <?xml version="1.0" encoding="UTF-8"?>
    
    <project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
      xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
      <modelVersion>4.0.0</modelVersion>
    
      <groupId>sipc</groupId>
      <artifactId>food</artifactId>
      <version>1.0-SNAPSHOT</version>
      <packaging>war</packaging>
    
      <name>food Maven Webapp</name>
      <!-- FIXME change it to the project's website -->
      <url>http://www.example.com</url>
    
      <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.7</maven.compiler.source>
        <maven.compiler.target>1.7</maven.compiler.target>
      </properties>
    
      <dependencies>
        <dependency>
          <groupId>junit</groupId>
          <artifactId>junit</artifactId>
          <version>4.11</version>
          <scope>test</scope>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-core</artifactId>
          <version>5.1.8.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-context</artifactId>
          <version>5.1.8.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>org.springframework</groupId>
          <artifactId>spring-beans</artifactId>
          <version>5.1.8.RELEASE</version>
        </dependency>
        <dependency>
          <groupId>commons-logging</groupId>
          <artifactId>commons-logging</artifactId>
          <version>1.2</version>
        </dependency>
        <dependency>
          <groupId>log4j</groupId>
          <artifactId>log4j</artifactId>
          <version>1.2.17</version>
        </dependency>
      </dependencies>
    
      <build>
        <finalName>food</finalName>
        <pluginManagement><!-- lock down plugins versions to avoid using Maven defaults (may be moved to parent pom) -->
          <plugins>
            <plugin>
              <artifactId>maven-clean-plugin</artifactId>
              <version>3.1.0</version>
            </plugin>
            <!-- see http://maven.apache.org/ref/current/maven-core/default-bindings.html#Plugin_bindings_for_war_packaging -->
            <plugin>
              <artifactId>maven-resources-plugin</artifactId>
              <version>3.0.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-compiler-plugin</artifactId>
              <version>3.8.0</version>
            </plugin>
            <plugin>
              <artifactId>maven-surefire-plugin</artifactId>
              <version>2.22.1</version>
            </plugin>
            <plugin>
              <artifactId>maven-war-plugin</artifactId>
              <version>3.2.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-install-plugin</artifactId>
              <version>2.5.2</version>
            </plugin>
            <plugin>
              <artifactId>maven-deploy-plugin</artifactId>
              <version>2.8.2</version>
            </plugin>
          </plugins>
        </pluginManagement>
      </build>
    </project>
  1. 创建applicationContext.xml

  2. 创建接口

  3. 继承接口

  4. SpringDemo1

    package ioc.demo1;
    
    

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringDemo1 {
@Test
public void demo1(){
UserService userService=new UserServiceImpl();
userService.sayHello();
}
@Test
// spring的方式实现
public void demo2(){
//创建Spring的工厂
ApplicationContext applicationContext=new ClassPathXmlApplicationContext(“applicationContext.xml”);
//通过工厂获得类
UserService userService=(UserService) applicationContext.getBean(“userService”);

       userService.sayHello();

   }

}


### IOC和DI的概念

- IOC  Inverse of Control 反转控制的概念,就是将原本在程序中手动创建UserService对象的控制权,交由

  Spring框架处理

- 简单说,就是创建UserService对象控制权被反转到了Spring框架

- DI Dependency Injection 依赖注入的概念,就是在Spring创建这个对象的过程中,

  将这个对象所依赖的属性注入进去

```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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--UserService的创建权交给了Spring-->
    <bean id="userService" class="ioc.demo1.UserServiceImpl">
        <!--控制反转-->
        <!--设置属性-->
        <property name="name" value="李四"/>
        <!--依赖注入-->
    </bean>
</beans>

Spring Bean管理

三种实例化Bean的方式

  • 使用类构造器实例化(默认无参数)

    1. 创建java/demo2/Bean1
    package demo2;
    
    //实例化的三种方式:采用无参数的构造方法的参数
    public class Bean1 {
        public Bean1(){
    
        }
    }
    1. 配置spring config applicationContext.xml
    <bean id="bean1" class="demo2.Bean1"/>
    3. SpringDemo2中(测试)
    package demo2;
    
    import org.junit.Test;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.support.ClassPathXmlApplicationContext;
    
    public class SpringDemo2 {
        @Test
        public void demo1(){
            //创建工厂
            ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
            //通过工厂获得类的实例
            Bean1 bean1= (Bean1) applicationContext.getBean("bean1");
        }
    }
  • 使用静态工厂方法实例化(简单工厂模式)

    1. 创建java/demo2/Bean2
    package demo2;
    //静态工厂实例化方式
    public class Bean2 {
    
    }
    
    1. 创建demo2/Bean2Factory
    package demo2;
    
    public class Bean2Factory {
        //第二种:Bean2的静态工厂
        public static Bean2 createBean2(){
            System.out.println("Bean2Factory的方法已经执行了");
            return new Bean2();
        }
    }
    
    



  3. applicationContext.xml

     ```xml
      <bean id="bean2" class="demo2.Bean2Factory" factory-method="createBean2"/>

     ```



  4. SpringDemo2中(包含bean3)

  ```java
  package demo2;

  import org.junit.Test;
  import org.springframework.context.ApplicationContext;
  import org.springframework.context.support.ClassPathXmlApplicationContext;

  public class SpringDemo2 {
      @Test
      public void demo1(){
          //创建工厂
          ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
          //通过工厂获得类的实例
          Bean1 bean1= (Bean1) applicationContext.getBean("bean1");
      }
      public void demo2(){
          //创建工厂
          ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
          //通过工厂获得类的实例
          Bean2 bean2= (Bean2) applicationContext.getBean("bean2");
      }
      public void demo3(){
          //创建工厂
          ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
          //通过工厂获得类的实例
          Bean3 bean3= (Bean3) applicationContext.getBean("bean3");
      }
  }
  • 使用实例工厂方法实例化(工厂方法模式)
  1. java/demo2/Bean3
package demo2;
//第三种:实例工厂实例化的方式
public class Bean3 {

}

  1. demo2/Bean3Factory
package demo2;

public class Bean3Factory {
    public Bean3 createBean3(){
        System.out.println("Bean3Factory被执行了");
        return new Bean3();
    }
}
  1. applicationContext.xml
<bean id="bean3Factory" class="demo2.Bean3Factory"/>
<bean id="bean3" factory-bean="bean3Factory" factory-method="createBean3"/>
  1. SpringDemo2
package demo2;

import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class SpringDemo2 {
    @Test
    public void demo1(){
        //创建工厂
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过工厂获得类的实例
        Bean1 bean1= (Bean1) applicationContext.getBean("bean1");
    }
    public void demo2(){
        //创建工厂
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过工厂获得类的实例
        Bean2 bean2= (Bean2) applicationContext.getBean("bean2");
    }
    public void demo3(){
        //创建工厂
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        //通过工厂获得类的实例
        Bean3 bean3= (Bean3) applicationContext.getBean("bean3");
    }
}

Bean的配置

  • id和name
    • 一般情况下,装配一个Bean时,通过指定一个id属性作为Bean的名称
    • id 属性在IOC容器中必须是唯一的
    • 如果Bean的名称中含有特殊字符,就需要使用name属性
  • class
    • class用于设置一个类的完全路径名称,主要作用是IOC容器生成类的实例

Bean的作用域

类别 说明
singleton 在SpringIOC容器中仅存在一个Bean实例,Bean以单实例的方式存在
prototype 每次调用getBean()时都会返回一个新的实例
request 每次HTTP请求都会创建一个新的Bean,该作用域仅适用于WebApplicationContext环境
session 同一个HTTP Session共享一个Bean,不同的HTTP Session使用不同的Bean,该作用域仅适用于WebApplicationContext环境

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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">
    <!--Bean的作用范围-->
    <bean id="person" class="com.majiajun.demo3.Person" scope="prototype"/>
</beans>

demo3/Person

package com.majiajun.demo3;

public class Person {

}

demo3/SpringDemo3

package com.majiajun.demo3;

import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

/*Bean作用范围的测试*/
public class SpringDemo3 {
    @Test
    public void demo1(){
        ApplicationContext applicationContext=new ClassPathXmlApplicationContext("applicationContext.xml");
        Person person= (Person) applicationContext.getBean("person");
        Person person1=(Person) applicationContext.getBean("person");
        System.out.println(person);
        System.out.println(person1);
    }
}

Bean的生命周期

<bean id="man" class="demo3.Man" init-method="setup" destroy-method="teardown"></bean>

Bean的生命周期的完整过程

  1. instantiate bean对象实例化

    public class Man(){
        public Man(){
            System.out.println("第一步:对象的实例化");
        }
    }
  2. poprlate properties封装属性

    public class Man{
        private String name;
    
        public void setName(String name) {
            System.out.println("第二步:设置属性");
            this.name = name;
        }
  3. 如果Bean实现BeanNameAware执行setBeanName

  4. 如果Bean实现BeanFactoryAware或者ApplicationContextAware设置工厂 setBeanFactory或者上下文对象setApplicationContext

    public class Man implements BeanNameAware, ApplicationContextAware {
        private String name;
    
        public void setName(String name) {
            System.out.println("设置属性");
            this.name = name;
        }
    
        public Man(){
            System.out.println("Man被实例化");
        }
        public void setup(){
            System.out.println("Man被初始化");
        }
        public void teardown(){
            System.out.println("Man被销毁了");
        }
    
        @Override
        public void setBeanName(String s) {
            System.out.println("第三步:设置Bean的");
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            System.out.println("第四步:了解工厂的信息");
        }
    }
  5. 如果存在类实现BeanPostProcessor(后处理Bean),执行postProcessBeforeInitialization

    package com.majiajun.demo3;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.config.BeanPostProcessor;
    
    public class MyBeanProcessor implements BeanPostProcessor {
        @Override
        public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("第五步:初始化前方法");
            return bean;
        }
    
        @Override
        public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
            System.out.println("第八步:初始化后方法");
            return bean;
        }
    }
  6. 如果Bean实现InitializingBean执行afterPropertiesSet

    package com.majiajun.demo3;
    
    import org.springframework.beans.BeansException;
    import org.springframework.beans.factory.BeanNameAware;
    import org.springframework.beans.factory.InitializingBean;
    import org.springframework.context.ApplicationContext;
    import org.springframework.context.ApplicationContextAware;
    
    public class Man implements BeanNameAware, ApplicationContextAware, InitializingBean {
        private String name;
    
        public void setName(String name) {
            System.out.println("设置属性");
            this.name = name;
        }
    
        public Man(){
            System.out.println("Man被实例化");
        }
        public void setup(){
            System.out.println("Man被初始化");
        }
        public void teardown(){
            System.out.println("Man被销毁了");
        }
    
        @Override
        public void setBeanName(String s) {
            System.out.println("第三步:设置Bean的");
        }
    
        @Override
        public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
            System.out.println("第四步:了解工厂的信息");
        }
    
        @Override
        public void afterPropertiesSet() throws Exception {
            System.out.println("第六步:属性设置后");
        }
    }
    
  7. 调用指定初始化方法init

  8. 如果存在类实现BeanPostProcessor(后处理Bean),执行postProcessAfterInitialization

  9. 执行业务处理(自己定义的方法),如下

    public class Man{
         public void run(){
            System.out.println("第九步:执行业务方法");
        }
    }
  10. 如果Bean实现DisposableBean执行destory

    public class Man implements DisposableBean{
        public void destory()throws Exception{
            System.out.println("第十步:执行Spring的销毁方法");
        }
    }
  11. 调用指定销毁方法customerDestory

Spring容器中Bean的生命周期

  • 演示如何增强一个类中的方法

Spring的属性注入

  • 对于类成员变量,注入方式有三种

    • 构造函数注入
      • 通过构造方法注入Bean的属性值或依赖的对象,它保证了Bean实例在实例化后就可以使用
    • 属性settrt方法注入
    • 接口注入
  • Spring支持前两种


javaweb     

本博客所有文章除特别声明外,均采用 CC BY-SA 3.0协议 。转载请注明出处!