Spring

1,什么是Spring?

Spring 显而易见英文单词:春天 的意思

2002年,Rod Jahnson首次推出了Spring框架雏形interface21框架。

2004年3月24日,Spring框架以interface21框架为基础,经过重新设计,发布了1.0正式版。

官网 : http://spring.io/

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

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

同样也可以使用maven引入依赖

<!--spring依赖的引入-->
    <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.23</version>
    </dependency>
  </dependencies>

2,Spring的优点是什么?

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

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

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

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

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

详细介绍可以看官方文档

3,SpringIOC的详细介绍

从上面可以看出Spring的优点很多,但是对于其核心IOC与AOP可能有人还不是很清楚什么是IOC什么是AOP

那么接下来我们就来看一下IOC

什么是IOC?

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

如何理解好IOC呢?说白了Ioc的关键是要明确“谁控制谁,控制什么,为何是反转(有反转就应该有正转了),哪些方面反转了

为什么要有IOC?

代码书写现状:耦合度太高,我们修改一处代码,往往要修改很多出相关联的代码。

比如我们有一个功能是获取用户数据,我们使用Dao层实现这个功能,再在Service层调用这个功能。但是我们每增加一个接口,比如获取mysql中的数据,就要修改原来的代码,如果再增加一个新的接口,又需要去service实现类中修改对应的实现。

解决方法:我们在创建对象的时候,不自己创建而是由外部提供对象

因此出现了IOC 对象的创建权由程序转移到外部,这种思想叫做控制反转。

IOC的核心概念

  • 使用对象时候由主动new对象转换成由外部提供对象,此过程中对象的创建权由程序转移到外部,这种思想叫做控制反转
  • Spring技术对此提供的实现
  • Spring提供了一个容器,称为IOC容器,用来充当IOC思想中的外部
  • IOC容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在IOC容器中统称为Bean。

IOC的实现主要依靠DI依赖注入 在容器中建立bean与bean之间的依赖关系

而DI依赖注入的方式也分很多

DI依赖注入方式

我们根据bean.xml中bean对象中属性的添加方式 对应不同依赖注入方式,在某个bean中其可能需要用到其他实体类作为属性,那么此时也不用自己new,IOC容器给你提供,那么如何提供呢?那就是这个bean你得给IOC容器一个入口 即 set方法 或者构造器方法

1,set方式注入

Dao层

public class UserDao {
    public void test(){
        System.out.println("UserDao Test....");
    }
}

Service层

/**
 * Set方法注入
 *      1,属性字段提供set方法
 *      2,在配置文件中通过property属性指定属性字段
 * */
public class UserService {
    //手动实例化
//    UserDao userDao=new UserDao();

    //业务逻辑对象    JavaBean对象   set方法注入

    //JavaBean对象
    private UserDao ud;
    public void setUd(UserDao ud) {
        this.ud = ud;
    }

    //常用对象(日期类型,String对象)
    private String host;
    public void setHost(String host) {
        this.host = host;
    }

    //基本对象
    private Integer port;
    public void setPort(Integer port) {
        this.port = port;
    }

    //List集合
    private List<String> list;
    public void setList(List<String> list) {
        this.list = list;
    }
    public void printList(){
        list.forEach(n -> System.out.println(n));
    }

    //Set集合
    private Set<String> set;
    public void setSet(Set<String> set) {
        this.set = set;
    }
    public void printSet(){
        set.forEach(n -> System.out.println(n));
    }

    //Map集合
    private Map<String,Object> map;
    public void setMap(Map<String, Object> map) {
        this.map = map;
    }
    public void printMap(){
        map.forEach((k,v) -> System.out.println(k+"---"+v));
    }

    //properties属性对象
    private Properties properties;
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
    public void printproperties(){
        properties.forEach((k,v) -> System.out.println(k+"---"+v));
    }

    public void test(){
        System.out.println("UserService Test....");
        ud.test();

        //常用对象
        System.out.println(host);

        //基本类型
        System.out.println(port);

        //List集合
        printList();
        //Set集合
        printSet();
        //Map集合
        printMap();
        //porperties属性对象
        printproperties();
    }

}

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

    <!--
         Set方法注入
              通过property属性注入
                    name:bean对象中属性字段的名称
                    ref:指定bean标签的id属性值
    -->
    <bean id="userService" class="com.xxxx.service.UserService">
        <!--  JavaBean对象注入-->
        <property name="ud" ref="userDao"/>
        <!--    常用对象string注入-->
        <property name="host" value="127.0.0.1"/>
        <!--    基本类型注入-->
        <property name="port" value="8080"/>
        <!--    List集合-->
        <property name="list">
            <list>
                <value>北京</value>
                <value>上海</value>
                <value>广州</value>
            </list>
        </property>
        <!--    Set集合-->
        <property name="set">
            <set>
                <value>北京BJ</value>
                <value>上海SH</value>
                <value>广州GZ</value>
            </set>
        </property>
        <!--    Map集合-->
        <property name="map">
            <map>
                <entry>
                    <key><value>周杰伦</value></key>
                    <value>青花瓷</value>
                </entry>
                <entry>
                    <key><value>周深</value></key>
                    <value>大鱼海棠</value>
                </entry>
                <entry>
                    <key><value>林俊杰</value></key>
                    <value>JJ</value>
                </entry>
            </map>
        </property>
        <!--    properties属性对象-->
        <property name="properties">
            <props>
                <prop key="ds">屌丝</prop>
                <prop key="hhh">哈哈哈</prop>
                <prop key="cj">菜鸡</prop>
            </props>
        </property>
    </bean>
    <bean id="userDao" class="com.xxxx.dao.UserDao"></bean>
</beans>

测试

public class starter01 {
    public static void main(String[] args) {
        ApplicationContext ac=new ClassPathXmlApplicationContext("spring.xml");

        UserService userService= (UserService) ac.getBean("userService");
        userService.test();
    }
}

我们先通过获取到的IOC容器,然后再通过IOC容器获取到Bean,然后底层是通过反射创建这个bean对象,然后这个bean当中可能存在一些依赖关系,那么的话这个时候IOC容器会调用set方法对这些属性进行注入。

2,构造器注入

属性的添加方式是 constructor

Dao层

public class UserDao02 {
    public void test(){
        System.out.println("UserDao02 Test....");
    }
}

Service层

/**
 * 构造器方法注入
 *      必须含有构造方法
 * */
public class UserService02 {
    private UserDao02 userDao02;

//    public UserService02(UserDao02 userDao02) {
//        this.userDao02 = userDao02;
//    }

    private Integer age;

    public UserService02(UserDao02 userDao02, Integer age) {
        this.userDao02 = userDao02;
        this.age = age;
    }

    public void test(){
        System.out.println("UserService02 Test....");
        userDao02.test();
    }

}

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

    <!--
         构造器方法注入
            设置构造器所需的参数
            通过constructor-arg标签设置构造器的参数
              构造器中有几个参数就要设置几个
                name:UserService02中定义的属性名称
                ref:要注入的bean对象对应的bean标签id属性值
                value:数据具体值
                index:参数的位置


          如果出现 循环依赖问题只有通过set方法注入
    -->
    <bean id="userService02" class="com.xxxx.service.UserService02">
        <constructor-arg name="userDao02" ref="userDao02"></constructor-arg>
        <constructor-arg name="age" value="18"></constructor-arg>
    </bean>
    <bean id="userDao02" class="com.xxxx.dao.UserDao02"></bean>



</beans>

测试

public class starter02 {
    public static void main(String[] args) {
        ApplicationContext ac=new ClassPathXmlApplicationContext("spring02.xml");

        UserService02 userService02= (UserService02) ac.getBean("userService02");
        userService02.test();
    }
}

我们通过构造器注入这个属性,我们配置文件中将Dao这个属性的添加方式提供了,那么接下来就是IOC容器调用构造方法将bean.xml文件中的属性注入到相关service

依赖的自动装配
  • 概念:IOC容器根据bean所依赖的资源在容器中自动查找 并注入到bean的过程叫做 自动装配
  • bean.xml 那么这个里头的话 我们就不要再写 property 因为我们是自动查找依赖 一般使用的是按类型
<!--  配置bean对象-->
    <bean id="userService" class="com.xxxx.service.UserService"></bean>
    <bean id="userDao" class="com.xxxx.dao.UserDao" ></bean>

自动装配注意事项
自动装配用于引用类型依赖注入,不能对简单类型进行操作
使用按类型装配时(byType)必须保障容器中相同类型的bean唯一,推荐使用
使用按名称装配时(byName)必须保障容器中具有指定名称的bean,因变量名与配置耦合,不推荐使用
自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效

注解开发模式的依赖注入
Dao层:
   @Repository
service层:
   @Service
controller层:
   @Controller
其他层:
   @Component
IOC容器就会扫描容器中的bean   
   @Autowired  或  @Resource

一个实例带你将快速了解注解模式

controller层

@Controller
public class TypeController {
    @Resource
    private TypeService typeService;

    public void test(){
        System.out.println("TypeController ....");
        typeService.test();
    }
}

service层

@Service
public class TypeService {
    @Resource
    private TypeDao typeDao;


    public void test(){
        System.out.println("TypeService Test....");
        typeDao.test();

    }

}

dao层

@Repository
public class TypeDao {
    public void test(){
        System.out.println("TypeDao Test....");
    }
}

spring02.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"
       xmlns:context="http://www.springframework.org/schema/context"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
         http://www.springframework.org/schema/context
          https://www.springframework.org/schema/context/spring-context.xsd">
        <!--
            Spring IOC扫描器
                作用:bean对象的统一管理,简化开发配置,提高效率

                1,设置自动化扫描范围
                    如果bean对象在扫描范围可以生效,否则无效
                2,在需要被实例化的JavaBean的类上添加注解(注解声明在类级别)  (bean对象 的id属性默认是 类的首字母小写)

                     Dao层:
                        @Repository
                     service层:
                        @Service
                     controller层:
                        @Controller
                     其他层:
                        @Component

                   注:开发过程中建议按照规则声明注解
        -->
    <!--   设置自动化扫描的范围-->
    <context:component-scan base-package="com.xxxx"/>
</beans>

测试

public class App02
{
    public static void main( String[] args ) {

        ApplicationContext ac=new ClassPathXmlApplicationContext("spring02.xml");

        TypeController typeController= (TypeController) ac.getBean("typeController");
        typeController.test();

    }

}