Spring学习笔记整理

1. Spring

1.1 简介

Spring理念 : 使现有技术更加实用 . 本身就是一个大杂烩 , 整合现有的框架技术

  • 官网 : http://spring.io/

  • 官方下载地址 : https://repo.spring.io/libs-release-local/org/springframework/spring/

  • GitHub : https://github.com/spring-projects

1.2 优点

  1. Spring是一个开源免费的框架 , 容器 .
  2. Spring是一个轻量级的框架 , 非侵入式的 .
  3. 控制反转 IoC , 面向切面 Aop
  4. 对事物的支持 , 对框架的支持

总结:

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

1.3 组成

image-20210128171530656

组成 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。

1.4 拓展

image-20210128171652966

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,属于依赖的关系。
  • Spring Boot在Spring Cloud中起到了承上启下的作用,如果你要学习Spring Cloud必须要学习Spring Boot

2. IOC理论推导

<dependencies>
    <!--https://mvnrepository.com/artifact/org.springframework/spring-webmvc-->
    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-webmvc</artifactId>
        <version>5.2.3.RELEASE</version>
    </dependency>
</dependencies>

案例一:

原来的写代码方式:

  1. UserDao接口

    public interface UserDao {
       public void getUser();
    }
    
  2. UserDao实现类

    public class UserDaoImpl implements UserDao {
       @Override
       public void getUser() {
           System.out.println("获取用户数据");
      }
    }
    
  3. UserService接口

    public interface UserService {
       public void getUser();
    }
    
  4. Service实现类

    public class UserServiceImpl implements UserService {
       private UserDao userDao = new UserDaoImpl();
    
       @Override
       public void getUser() {
           userDao.getUser();
      }
    }
    
  5. 测试

    @Test
    public void test(){
       UserService service = new UserServiceImpl();
       service.getUser();
    }
    

这是我们原来的方式 , 开始大家也都是这么去写的对吧 . 那我们现在修改一下 .

把Userdao的实现类增加一个 .

public class UserDaoMySqlImpl implements UserDao {
   @Override
   public void getUser() {
       System.out.println("MySql获取用户数据");
  }
}

紧接着我们要去使用MySql的话 , 我们就需要去service实现类里面修改对应的实现

public class UserServiceImpl implements UserService {
   private UserDao userDao = new UserDaoMySqlImpl();

   @Override
   public void getUser() {
       userDao.getUser();
  }
}

在假设, 我们再增加一个Userdao的实现类 .

public class UserDaoOracleImpl implements UserDao {
   @Override
   public void getUser() {
       System.out.println("Oracle获取用户数据");
  }
}

那么我们要使用Oracle , 又需要去service实现类里面修改对应的实现 . 假设我们的这种需求非常大 , 这种方式就根本不适用了, 甚至反人类对吧 , 每次变动 , 都需要修改大量代码 . 这种设计的耦合性太高了, 牵一发而动全身 .

那我们如何去解决呢 ?

我们可以在需要用到他的地方 , 不去实现它 , 而是留出一个接口 , 利用set , 我们去代码里修改下 .

public class UserServiceImpl implements UserService {
   private UserDao userDao;
// 利用set实现
   public void setUserDao(UserDao userDao) {
       this.userDao = userDao;
  }

   @Override
   public void getUser() {
       userDao.getUser();
  }
}

现在去我们的测试类里 , 进行测试 ;

@Test
public void test(){
   UserServiceImpl service = new UserServiceImpl();
   service.setUserDao( new UserDaoMySqlImpl() );
   service.getUser();
   //那我们现在又想用Oracle去实现呢
   service.setUserDao( new UserDaoOracleImpl() );
   service.getUser();
}

以前所有东西都是由程序去进行控制创建 , 而现在是由我们自行控制创建对象 , 把主动权交给了调用者 . 程序不用去管怎么创建,怎么实现了 . 它只负责提供一个接口 .

这种思想 , 从本质上解决了问题 , 我们程序员不再去管理对象的创建了 , 更多的去关注业务的实现 . 耦合性大大降低 . 这也就是IOC的原型 !

IOC本质

控制反转IoC(Inversion of Control),是一种设计思想,DI(依赖注入)是实现IoC的一种方法,也有人认为DI只是IoC的另一种说法。没有IoC的程序中 , 我们使用面向对象编程 , 对象的创建与对象间的依赖关系完全硬编码在程序中,对象的创建由程序自己控制,控制反转后将对象的创建转移给第三方,个人认为所谓控制反转就是:获得依赖对象的方式反转了。

image-20210129101923601

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

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

3. HelloSpring

案例二:HelloSpring

导入Jar包:

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

<dependency>
   <groupId>org.springframework</groupId>
   <artifactId>spring-webmvc</artifactId>
   <version>5.1.10.RELEASE</version>
</dependency>

编写代码

  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 );
  }
}
  1. 编写我们的spring文件 , 这里我们命名为beans.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就是java对象 , 由Spring创建和管理-->
   <bean id="hello" class="com.kuang.pojo.Hello">
       <property name="name" value="Spring"/>
   </bean>

</beans>
  1. 我们可以去进行测试了 .
@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去浏览一下底层源码

案例一:

我们在案例一中, 新增一个Spring配置文件beans.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 id="MysqlImpl" class="com.kuang.dao.impl.UserDaoMySqlImpl"/>
   <bean id="OracleImpl" class="com.kuang.dao.impl.UserDaoOracleImpl"/>

   <bean id="ServiceImpl" class="com.kuang.service.impl.UserServiceImpl">
       <!--注意: 这里的name并不是属性 , 而是set方法后面的那部分 , 首字母小写-->
       <!--引用另外一个bean , 不是用value 而是用 ref-->
       <property name="userDao" ref="OracleImpl"/>
   </bean>

</beans>

测试

@Test
public void test2(){
   ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
   UserServiceImpl serviceImpl = (UserServiceImpl) context.getBean("ServiceImpl");
   serviceImpl.getUser();
}

**不用在程序中去改动,要实现不同的操作,只需要在xml配置文件中进行修改,所谓的IoC,一句话搞定:对象由Spring 来创建,管理,装配 ! **

4. IOC创建对象方式

  1. 使用无参构造创建对象,默认

    1. 创建无参对象

      public class User {
          private String name;
          
          public User() {
              System.out.println("User的无参构造");
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public void show() {
              System.out.println("name=" + name);
          }
      }
      
    2. 创建beans.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 id="user" class="com.huang.pojo.User">
             <property name="name" value="小黄"/>
         </bean>
      </beans>
      
    3. 测试

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

    1. 创建有参对象

      public class User {
          private String name;
      
          public User(String name) {
              this.name = name;
          }
      
          public String getName() {
              return name;
          }
      
          public void setName(String name) {
              this.name = name;
          }
      
          public void show() {
              System.out.println("name=" + name);
          }
      }
      
    2. 创建beans.xml(三种方式)

      1. 下标赋值

        <!--第一种:下表赋值-->
        <bean id="user" class="com.huang.pojo.User">
            <constructor-arg index="0" value="黄蓓"/>
        </bean>
        
      2. 类型

        <!--第二种:通过类型创建,不建议使用-->
        <bean id="user" class="com.huang.pojo.User">
            <constructor-arg type="java.lang.String" value="黄黄"/>
        </bean>
        
      3. 参数名

        <!--第三种:直接通过参数名来设置-->
        <bean id="user" class="com.huang.pojo.User">
            <constructor-arg name="name" value="蓓蓓"/>
        </bean>
        
    3. 测试

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

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

5. Spring配置

5.1 别名

<!--设置别名-->
<alias name="user" alias="userNew"/>

5.2 Bean配置

<!--bean就是java对象,由Spring创建和管理-->

<!--
	id 是bean的标识符,要唯一,如果没有配置id,name就是默认标识符
	如果配置id,又配置了name,那么name是别名
	name可以设置多个别名,可以用逗号,分号,空格隔开
	如果不配置id和name,可以根据applicationContext.getBean(.class)获取对象;
	class是bean的全限定名=包名+类名
-->
<bean id="hello" name="hello2 h2,h3;h4" class="com.kuang.pojo.Hello">
   <property name="name" value="Spring"/>
</bean>

5.3 import

import用于团队合作开发,在applicationContext.xml中导入import

<import resource="beans.xml"/>

6. 依赖注入

6.1 构造器注入

前面已讲

6.2 Set方式注入(重点)

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

【环境搭建】

  1. 复杂类型

    public class Address {
        private String address;
    
        public String getAddress() {
            return address;
        }
    
        public void setAddress(String address) {
            this.address = address;
        }
    }
    
  2. 真实测试对象

    public class Student {
        private String name;
        private Address address;
        private String[] books;
        private List<String> hobbies;
        private Map<String, String> card;
        private Set<String> games;
        private String wife;
        private Properties info;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public Address getAddress() {
            return address;
        }
    
        public void setAddress(Address address) {
            this.address = address;
        }
    
        public String[] getBooks() {
            return books;
        }
    
        public void setBooks(String[] books) {
            this.books = books;
        }
    
        public List<String> getHobbies() {
            return hobbies;
        }
    
        public void setHobbies(List<String> hobbies) {
            this.hobbies = hobbies;
        }
    
        public Map<String, String> getCard() {
            return card;
        }
    
        public void setCard(Map<String, String> card) {
            this.card = card;
        }
    
        public Set<String> getGames() {
            return games;
        }
    
        public void setGames(Set<String> games) {
            this.games = games;
        }
    
        public String getWife() {
            return wife;
        }
    
        public void setWife(String wife) {
            this.wife = wife;
        }
    
        public Properties getInfo() {
            return info;
        }
    
        public void setInfo(Properties info) {
            this.info = info;
        }
    }
    
  3. beans.xml

    <bean id="student" class="com.huang.pojo.Student">
        <property name="name" value="蓓蓓"/>
    </bean>
    
  4. 测试类

    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        Student student = (Student)context.getBean("student");
        String name = student.getName();
        System.out.println(name);
    }
    

完善注入信息

<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="address" class="com.huang.pojo.Address">
        <property name="address" value="北京"/>
    </bean>

    <bean id="student" class="com.huang.pojo.Student">
        <!--普通值注入-->
        <property name="name" value="小黄"/>
        <!--Bean注入-->
        <property name="address" ref="address"/>
        <!--数组注入-->
        <property name="books">
            <array>
                <value>红楼梦</value>
                <value>西游记</value>
                <value>三国演义</value>
                <value>水浒传</value>
            </array>
        </property>
        <!--list注入-->
        <property name="hobbies">
            <list>
                <value>sing</value>
                <value>dance</value>
                <value>skate</value>
            </list>
        </property>
        <!--map-->
        <property name="card">
            <map>
                <entry key="身份证" value="32068219971218100X"/>
                <entry key="银行卡" value="326012345678910256"/>
            </map>
        </property>
        <!--set-->
        <property name="games">
            <set>
                <value>lol</value>
                <value>coc</value>
                <value>bob</value>
            </set>
        </property>
        <!--null-->
        <property name="wife">
            <null/>
        </property>
        <!--Properties-->
        <property name="info">
            <props>
                <prop key="学号">16031012</prop>
                <prop key="性别"></prop>
                <prop key="电话">15189778730</prop>
            </props>
        </property>
    </bean>
</beans>

6.3 拓展方式注入(c命名、p命名)

暂时不需要

6.4 Bean的作用域

image-20210129161949357

  1. 单例模式(Spring默认机制)

    <bean id="ServiceImpl" class="cn.csdn.service.ServiceImpl" scope="singleton">
    
  2. 原型模式:每次从容器中get的时候,都会产生一个新对象

    <bean id="account" class="com.foo.DefaultAccount" scope="prototype"/> 
    
  3. 其余的request、session、application,只能在web开发中使用到

    <bean id="loginAction" class=cn.csdn.LoginAction" scope="request"/>
    
    <bean id="userPreferences" class="com.foo.UserPreferences" scope="session"/>
    

7. Bean的自动装配

  • 自动装配是Spring满足bean依赖的一种方式
  • Spring会在上下文中自动寻找,并自动给bean装配属性

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

  1. 在xml中显式配置;
  2. 在java中显式配置;
  3. 隐式的bean发现机制和自动装配。

7.1 测试

环境搭建:一个人有两只宠物

  1. 新建一个项目
  2. 新建两个实体类,Cat、Dog都有一个叫的方法
public class Cat {
   public void shout() {
       System.out.println("miao~");
  }
}
public class Dog {
   public void shout() {
       System.out.println("wang~");
  }
}
  1. 新建一个用户类 People
public class People {
    private Cat cat;
    private Dog dog;
    private String name;

    public Cat getCat() {
        return cat;
    }

    public void setCat(Cat cat) {
        this.cat = cat;
    }

    public Dog getDog() {
        return dog;
    }

    public void setDog(Dog dog) {
        this.dog = dog;
    }

    public String getName() {
        return name;
    }

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

    @Override
    public String toString() {
        return "People{" +
                "cat=" + cat +
                ", dog=" + dog +
                ", name='" + name + '\'' +
                '}';
    }
}
  1. 编写Spring配置文件
<?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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="dog" class="com.huang.pojo.Dog"/>
    <bean id="cat" class="com.huang.pojo.Cat"/>

    <bean id="people" class="com.huang.pojo.People">
        <property name="cat" ref="cat"/>
        <property name="dog" ref="dog"/>
        <property name="name" value="huang"/>
    </bean>
</beans>
  1. 测试
public class MyTest {
    @Test
    public void test(){
        ApplicationContext context = new ClassPathXmlApplicationContext("beans.xml");
        People people = context.getBean("people", People.class);
        people.getDog().shout();
        people.getCat().shout();
    }
}

7.2 ByName自动装配

<bean id="dog" class="com.huang.pojo.Dog"/>
<bean id="cat" class="com.huang.pojo.Cat"/>
<!--
    byName:会自动在容器上下文中查找和自己对象set方法后面的值对应的beanid
    byType:会自动在容器上下文中查找和自己对象属性类型相同的bean
-->
<bean id="people" class="com.huang.pojo.People" autowire="byName">
    <property name="name" value="huang"/>
</bean>

7.3 ByType自动装配

<bean id="dog123" class="com.huang.pojo.Dog"/>
<bean id="cat" class="com.huang.pojo.Cat"/>
<!--
    byName:会自动在容器上下文中查找和自己对象set方法后面的值对应的beanid
    byType:会自动在容器上下文中查找和自己对象属性类型相同的bean
-->
<bean id="people" class="com.huang.pojo.People" autowire="byType">
    <property name="name" value="huang"/>
</bean>

总结

  • byName的时候,需要保证所有bean的id唯一,并且这个bean需要和自动注入的属性的set方法的值一致
  • byType的时候,需要保证所有bean的class唯一,并且这个bean需要和自动注入的属性的类型一致

7.4 使用注解实现自动装配

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值