SpringIOC

DI和IOC的概念
依赖注入和控制反转
谁控制谁:之前是我们自己来new对象,现在是springIOC容器来帮我们创建对象
控制什么:IOC容器帮我们控制的是我们需要的对象以及此对象需要依赖的对象(此对象的属性为另一个对象)
什么叫反转:之前是我们自己来new对象,现在是springIOC容器来帮我们创建对象
很多人把IOC和DI说成一个东西,笼统来说的话是没有问题的,但是本质上还是有所区别的,希望大家能够严谨一点,IOC和DI是从不同的角度描述的同一件事,IOC是从容器的角度描述,而DI是从应用程序的角度来描述,也可以这样说,IOC是设计思想,而DI是具体的实现方式
最重要作用的就是解耦

1.开始使用

1.添加maven依赖(ssm所有依赖)

<dependencies>
        <!-- https://mvnrepository.com/artifact/junit/junit -->
        <dependency>
            <groupId>junit</groupId>
            <artifactId>junit</artifactId>
            <version>4.12</version>
            <scope>test</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-context -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-context</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/cglib/cglib -->
        <dependency>
            <groupId>cglib</groupId>
            <artifactId>cglib</artifactId>
            <version>3.3.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.aspectj/aspectjweaver -->
        <dependency>
            <groupId>org.aspectj</groupId>
            <artifactId>aspectjweaver</artifactId>
            <version>1.9.5</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/aopalliance/aopalliance -->
        <dependency>
            <groupId>aopalliance</groupId>
            <artifactId>aopalliance</artifactId>
            <version>1.0</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-aspects</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.alibaba/druid -->
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>druid</artifactId>
            <version>1.1.21</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/MySQL/mysql-connector-java -->
        <dependency>
            <groupId>MySQL</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>5.1.40</version>
        </dependency>

        <!-- https://mvnrepository.com/artifact/org.springframework/spring-web -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-web</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.springframework/spring-webmvc -->
        <dependency>
            <groupId>org.springframework</groupId>
            <artifactId>spring-webmvc</artifactId>
            <version>5.2.3.RELEASE</version>
        </dependency>
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>servlet-api</artifactId>
            <version>2.5</version>
            <scope>provided</scope>
        </dependency>

        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jsp-api</artifactId>
            <version>2.0</version>
            <scope>provided</scope>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-core -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-core</artifactId>
            <version>2.10.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-databind -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-databind</artifactId>
            <version>2.10.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/com.fasterxml.jackson.core/jackson-annotations -->
        <dependency>
            <groupId>com.fasterxml.jackson.core</groupId>
            <artifactId>jackson-annotations</artifactId>
            <version>2.10.3</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/commons-io/commons-io -->
        <dependency>
            <groupId>commons-io</groupId>
            <artifactId>commons-io</artifactId>
            <version>2.6</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/commons-fileupload/commons-fileupload -->
        <dependency>
            <groupId>commons-fileupload</groupId>
            <artifactId>commons-fileupload</artifactId>
            <version>1.4</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/javax.servlet/jstl -->
        <dependency>
            <groupId>javax.servlet</groupId>
            <artifactId>jstl</artifactId>
            <version>1.2</version>
        </dependency>
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis</artifactId>
            <version>3.5.4</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
        <dependency>
            <groupId>mysql</groupId>
            <artifactId>mysql-connector-java</artifactId>
            <version>8.0.16</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/log4j/log4j -->
        <dependency>
            <groupId>log4j</groupId>
            <artifactId>log4j</artifactId>
            <version>1.2.17</version>
        </dependency>
        <!-- https://mvnrepository.com/artifact/org.mybatis/mybatis-spring -->
        <dependency>
            <groupId>org.mybatis</groupId>
            <artifactId>mybatis-spring</artifactId>
            <version>2.0.4</version>
        </dependency>

    </dependencies>

2.小细节
每次maven有改动之后调整一下jdk版本–>settiing-》java complier
spring是根据bean对象的set方法对属性进行注入的
new classpathxmlapplicationcontext创建对象(多例)
单例多例可以在xml容器中修改(scope=“property” 默认是单例)
多例的对象是指getbean之后创建的,而单例是xml容器初始化时创建的
3.创建spring.xml配置文件
添加命名空间

<!--此命名空间可以在bean标签内部为属性赋值-->
xmlns:p="http://www.springframework.org/schema/p"
<!--此命名空间可以引入集合map等工具类-->
xmlns:util="http://www.springframework.org/schema/util"

添加之后可以这么写

 <bean name="user2" class="com.spring.bean.User" p:name="wangwu" p:add-ref="address" p:age="5" p:id="2" p:gender="woman">
    </bean>

而正常的写法是这样的

<!--使用set方法进行值的注入-->
 <bean  id="user" class="com.spring.bean.User" scope="prototype">
        <property name="gender" value="man"> </property>
        <property name="age" value="10" > </property>
        <property name="id" value="1"> </property>
        <property name="name" value="zhangsan"> </property>
        <!--user类注入了myaddress类,要使用ref=“”-->
        <property name="add" ref="address"></property>
    </bean>
    <bean id="address" class="com.spring.bean.MyAddress">
        <property name="city" value="jixi"></property>
        <property name="province" value="heilongjiang"></property>
        <property name="countryside" value="jiguanqu"></property>
    </bean>
    <!-- 使用构造器对属性进行值的注入-->
    <bean id="user1" class="com.spring.bean.User">
        <constructor-arg name="name" value="lisi"></constructor-arg>
        <constructor-arg name="age" value="1"></constructor-arg>
        <constructor-arg name="id" value="1"></constructor-arg>
        <constructor-arg name="gender" value="man"></constructor-arg>
        <constructor-arg name="add" ref="address"></constructor-arg>
    </bean>

一些特殊的属性注入

<bean  id="user" class="com.spring.bean.User" scope="prototype">
        <property name="gender" >
            <array>
                <value>1</value>
                <value>1</value>
                <value>1</value>
            </array>
        </property>
        <property name="age"  > 
            <list>
                <value>1</value>
            </list>
        </property>
        <property name="id" value="1"> </property>
        <property name="name" value="zhangsan"> </property>
        <!--内部类-->
        <!--级联属性-->
        <property name="add.city" >
            <bean name="address" class="com.spring.bean.MyAddress">
                <property name="province" value="heilongjiang"></property>
                <property name="countryside" value="heilongjiang"></property>
                <property name="city" value="heilongjiang"></property>
            </bean>
        </property>
    </bean>
    
    <bean name="user2" class="com.spring.bean.User" p:name="wangwu" p:add-ref="address" p:age="5" p:id="2" p:gender="woman">
    </bean>
    <util:map id="map">
        <entry key="1" value="2"></entry>>
        <entry key="1" value="2"></entry>>
        <entry key="1" value="2"></entry>>
        <entry key="1" value="2"></entry>>
    </util:map>>

xml中bean的继承

 <bean id="person" class="com.mashibing.bean.Person">
        <property name="id" value="1"></property>
        <property name="name" value="zhangsan"></property>
        <property name="age" value="21"></property>
        <property name="gender" value=""></property>
    </bean>
    <!--parent:指定bean的配置信息继承于哪个bean-->
    <bean id="person2" class="com.mashibing.bean.Person" parent="person">
        <property name="name" value="lisi"></property>
    </bean>

xml中如果想实现Java文件的抽象类,不需要将当前bean实例化的话,可以使用abstract属性

	<bean id="person" class="com.mashibing.bean.Person" abstract="true">
        <property name="id" value="1"></property>
        <property name="name" value="zhangsan"></property>
        <property name="age" value="21"></property>
        <property name="gender" value=""></property>
    </bean>
    <!--parent:指定bean的配置信息继承于哪个bean-->
    <bean id="person2" class="com.mashibing.bean.Person" parent="person">
        <property name="name" value="lisi"></property>
    </bean>

使用工厂类创建对象

先定义一个工厂方法
class FactoryBean{
public static User getUser (){
	return new User();
	}
}
静态工厂
<!--
静态工厂的使用:
class:指定静态工厂类
factory-method:指定哪个方法是工厂方法
-->
<bean id="person5" class="com.mashibing.factory.PersonStaticFactory" factory-method="getPerson">
        <!--constructor-arg:可以为方法指定参数-->
        <constructor-arg value="lisi"></constructor-arg>
    </bean>

实例工厂

 <!--实例工厂使用-->
    <!--创建实例工厂类-->
    <bean id="personInstanceFactory" class="com.mashibing.factory.PersonInstanceFactory"></bean>
    <!--
    factory-bean:指定使用哪个工厂实例
    factory-method:指定使用哪个工厂实例的方法
    -->
    <bean id="person6" class="com.mashibing.bean.Person" factory-bean="personInstanceFactory" factory-method="getPerson">
        <constructor-arg value="wangwu"></constructor-arg>
    </bean>

在bean标签中的属性,使用哪个工厂类
factory-bean=" "
在bean标签中的属性,使用工厂类的什么方法来创建对象
factory-method=" "

继承factoryBean对象来实现工厂类

package com.mashibing.factory;

import com.mashibing.bean.Person;
import org.springframework.beans.factory.FactoryBean;

/**
 * 实现了FactoryBean接口的类是Spring中可以识别的工厂类,spring会自动调用工厂方法创建实例
 */
public class MyFactoryBean implements FactoryBean<Person> {

    /**
     * 工厂方法,返回需要创建的对象
     * @return
     * @throws Exception
     */
    @Override
    public Person getObject() throws Exception {
        Person person = new Person();
        person.setName("maliu");
        return person;
    }

    /**
     * 返回创建对象的类型,spring会自动调用该方法返回对象的类型
     * @return
     */
    @Override
    public Class<?> getObjectType() {
        return Person.class;
    }

    /**
     * 创建的对象是否是单例对象
     * @return
     */
    @Override
    public boolean isSingleton() {
        return false;
    }
}

bean对象的销毁

<!--bean生命周期表示bean的创建到销毁
        如果bean是单例,容器在启动的时候会创建好,关闭的时候会销毁创建的bean
        如果bean是多例,获取的时候创建对象,没有任何调用的时候销毁
    -->
    <bean id="address" class="com.mashibing.bean.Address" init-method="init" destroy-method="destory"></bean>
 ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        User user = context.getBean("user", User.class);
        System.out.println(user);
        Object user1 = context.getBean("user");
        System.out.println(user==user1);
        Object user2 = context.getBean("user2");
        System.out.println(user2);
        //销毁context,单例对象随之被销毁
        context.close();

bean对象初始化前后方法
实现BeanPostProcessor

public class InitMethod implements BeanPostProcessor {
    /**
     * 在初始化方法调用之前执行
     * @param bean  初始化的bean对象
     * @param beanName  xml配置文件中的bean的id属性
     * @return
     * @throws BeansException
     */
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之前调用"+beanName);
        return bean;
    }

    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("初始化之后调用"+beanName);
        return bean;
    }

引用外部配置文件

<?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       http://www.springframework.org/schema/beans/spring-beans.xsd        
http://www.springframework.org/schema/context        
http://www.springframework.org/schema/context/spring-context.xsd">   
 <!--加载外部配置文件        在加载外部依赖文件的时候需要context命名空间    -->    
 <context:property-placeholder location="classpath:dbconfig.properties"/>   
 <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">        
 <property name="username" value="${username}"></property>        
 <property name="password" value="${password}"></property>        
 <property name="url" value="${url}"></property>       
 <property name="driverClassName" value="${driverClassName}"></property>    
 </bean>
 </beans>

外部的数据源
username=root
password=123456
url=jdbc:mysql://localhost:3306/demo
driverClassName=com.mysql.jdbc.Driver

注意要点
在容器中引入外部配置文件时(jdbc)要注意数据库连接池的配置信息必须与容器中bean属性的name保持一致并且配置文件中的配置信息也必须保持一致
在这里插入图片描述
SPEL

<bean id="person4" class="com.mashibing.bean.Person">
        <!--支持任何运算符-->
        <property name="age" value="#{12*2}"></property>
        <!--可以引用其他bean的某个属性值-->
        <property name="name" value="#{address.province}"></property>
        <!--引用其他bean-->
        <property name="address" value="#{address}"></property>
        <!--调用静态方法-->
        <property name="hobbies" value="#{T(java.util.UUID).randomUUID().toString().substring(0,4)}"></property>
        <!--调用非静态方法-->
        <property name="gender" value="#{address.getCity()}"></property>
    </bean>

4.spring注解的使用
使用注解的方式注册bean到IOC容器中

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

    <!--
    如果想要将自定义的bean对象添加到IOC容器中,需要在类上添加某些注解
    Spring中包含4个主要的组件添加注解:
    @Controller:控制器,推荐给controller层添加此注解
    @Service:业务逻辑,推荐给业务逻辑层添加此注解
    @Repository:仓库管理,推荐给数据访问层添加此注解
    @Component:给不属于以上基层的组件添加此注解
    注意:我们虽然人为的给不同的层添加不同的注解,但是在spring看来,可以在任意层添加任意注解
           spring底层是不会给具体的层次验证注解,这样写的目的只是为了提高可读性,最偷懒的方式
           就是给所有想交由IOC容器管理的bean对象添加component注解

    使用注解需要如下步骤:
    1、添加上述四个注解中的任意一个
    2、添加自动扫描注解的组件,此操作需要依赖context命名空间
    3、添加自动扫描的标签context:component-scan

	注意:当使用注解注册组件和使用配置文件注册组件是一样的,但是要注意:
		1、组件的id默认就是组件的类名首字符小写,如果非要改名字的话,直接在注解中添加即可
		2、组件默认情况下都是单例的,如果需要配置多例模式的话,可以在注解下添加@Scope注解
    -->
    <!--
    定义自动扫描的基础包:
    base-package:指定扫描的基础包,spring在启动的时候会将基础包及子包下所有加了注解的类都自动
                扫描进IOC容器
    -->
    **<context:component-scan base-package="com.mashibing"></context:component-scan>
</beans>**

定义要排除的类

 <!--
        当定义好基础扫描的包之后,可以排除包中的某些类,使用如下的方式:
        type:表示指定过滤的规则
            annotation:按照注解进行排除,标注了指定注解的组件不要,expression表示要过滤的注解
            assignable:指定排除某个具体的类,按照类排除,expression表示不注册的具体类名
            aspectj:后面讲aop的时候说明要使用的aspectj表达式,不用
            custom:定义一个typeFilter,自己写代码决定哪些类被过滤掉,不用
            regex:使用正则表达式过滤,不用
        -->
<!--        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Controller"/>-->

        <!--指定只扫描哪些组件,默认情况下是全部扫描的,所以此时要配置的话需要在component-scan标签中添加 use-default-filters="false"-->
        <context:include-filter type="assignable" expression="com.mashibing.service.PersonService"/>
    </context:component-scan>

使用@AutoWired进行自动注入

​ 使用注解的方式实现自动注入需要使用@AutoWired注解。

PersonController.java

package com.mashibing.controller;

import com.mashibing.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Controller;

@Controller
public class PersonController {

    @Autowired
    private PersonService personService;

    public PersonController() {
        System.out.println("创建对象");
    }

    public void getPerson(){
        personService.getPerson();
    }
}

PersonService.java

package com.mashibing.service;

import com.mashibing.dao.PersonDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class PersonService {

    @Autowired
    private PersonDao personDao;

    public void getPerson(){
        personDao.getPerson();
    }
}

PersonDao.java

package com.mashibing.dao;

        import org.springframework.stereotype.Repository;

@Repository
public class PersonDao {

    public void getPerson(){
        System.out.println("PersonDao:getPerson");
    }
}

注意:当使用AutoWired注解的时候,自动装配的时候是根据类型实现的。
​ 1、如果只找到一个,则直接进行赋值,
​ 2、如果没有找到,则直接抛出异常,
​ 3、如果找到多个,那么会按照变量名作为id继续匹配,
​ 1、匹配上直接进行装配
​ 2、如果匹配不上则直接报异常
4、在调用的时候不可以new新对象,要使用spring容器中的bean

ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
        UserCtrl userCtrl = context.getBean("userCtrl", UserCtrl.class);
        userCtrl.getUser();

还可以使用@Qualifier注解来指定id的名称,让spring不要使用变量名,当使用@Qualifier注解的时候也会有两种情况:
​ 1、找到,则直接装配
​ 2、找不到,就会报错

PersonController.java

package com.mashibing.controller;

import com.mashibing.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

@Controller
public class PersonController {

    @Autowired
    @Qualifier("personService")
    private PersonService personServiceExt2;

    public PersonController() {
        System.out.println("创建对象");
    }

    public void getPerson(){
        personServiceExt2.getPerson();
    }
}

​ 通过上述的代码我们能够发现,使用@AutoWired肯定是能够装配上的,如果装配不上就会报错。

@AutoWired可以进行定义在方法上
​ 当我们查看@AutoWired注解的源码的时候发现,此注解不仅可以使用在成员变量上,也可以使用在方法上。

PersonController.java

package com.mashibing.controller;

import com.mashibing.dao.PersonDao;
import com.mashibing.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

@Controller
public class PersonController {

    @Qualifier("personService")
    @Autowired
    private PersonService personServiceExt2;

    public PersonController() {
        System.out.println("创建对象");
    }

    public void getPerson(){
        System.out.println("personController..."+personServiceExt2);
//        personServiceExt2.getPerson();
    }

     /**
     * 当方法上有@AutoWired注解时:
     *  1、此方法在bean创建的时候会自动调用
     *  2、这个方法的每一个参数都会自动注入值
     * @param personDao
     */
    @Autowired
    public void test(PersonDao personDao){
        System.out.println("此方法被调用:"+personDao);
    }
    
    /**
     * @Qualifier注解也可以作用在属性上,用来被当作id去匹配容器中的对象,如果没有
     * 此注解,那么直接按照类型进行匹配
     * @param personService
     */
    @Autowired
    public void test2(@Qualifier("personServiceExt") PersonService personService){
        System.out.println("此方法被调用:"+personService);
    }
}

自动装配的注解@AutoWired,@Resource

​ 在使用自动装配的时候,出了可以使用@AutoWired注解之外,还可以使用@Resource注解,大家需要知道这两个注解的区别。

​ 1、@AutoWired:是spring中提供的注解,@Resource:是jdk中定义的注解,依靠的是java的标准

​ 2、@AutoWired默认是按照类型进行装配,默认情况下要求依赖的对象必须存在,@Resource默认是按照名字进行匹配的,同时可以指定name属性。

​ 3、@AutoWired只适合spring框架,而@Resource扩展性更好

PersonController.java

package com.mashibing.controller;

import com.mashibing.dao.PersonDao;
import com.mashibing.service.PersonService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Controller;

import javax.annotation.Resource;

@Controller
public class PersonController {

    @Qualifier("personService")
    @Resource
    private PersonService personServiceExt2;

    public PersonController() {
        System.out.println("创建对象");
    }

    public void getPerson(){
        System.out.println("personController..."+personServiceExt2);
        personServiceExt2.getPerson();
    }

    /**
     * 当方法上有@AutoWired注解时:
     *  1、此方法在bean创建的时候会自动调用
     *  2、这个方法的每一个参数都会自动注入值
     * @param personDao
     */
    @Autowired
    public void test(PersonDao personDao){
        System.out.println("此方法被调用:"+personDao);
    }

    /**
     * @Qualifier注解也可以作用在属性上,用来被当作id去匹配容器中的对象,如果没有
     * 此注解,那么直接按照类型进行匹配
     * @param personService
     */
    @Autowired
    public void test2(@Qualifier("personServiceExt") PersonService personService){
        System.out.println("此方法被调用:"+personService);
    }
}

@qualifier注解可以让spring按照指定的名字作为id进行匹配

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值