Spring - IOC容器

底层原理

1、什么是IOC

(1)控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理。
(2)使用IOC目的:为了耦合度降低。
(3)做入门案例就是IOC实现。

2、IOC底层原理。

(1) xml解析、工厂模式、反射。

目的:耦合度降低最低限度 eg.实例一个类调用另一个类的方法

进一步解耦

在这里插入图片描述

IOC

在这里插入图片描述

3. IOC(接口)

1、IOC 思想基于IOC容器完成,IOC 容器底层就是对象工厂
2、Spring 提供IOC容器实现两种方式: (两个接口) 。
(1) BeanFactory: IOC 容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用。
*加载配置文件时候不会创建对象,在获取对象(使用)才去创建对象。
(2) ApplicationContext: BeanFactory 接口的子接口,提供更多更强大的功能,一般由开发人员进行使用。
*加载配置文件时候就会把在配置文件对象进行创建。
3、ApplicationContext 接口有实现类

在这里插入图片描述

Bean管理XML方式

1、什么是Bean管理
(0) Bean管理指的是两个操作。
(1) Spring 创建对象。
(2) Spirng 注入属性。

Bean 管理操作有两种方式

(1)基于xml配置文件方式实现。

①基于XML方式创建对象

在这里插入图片描述

​ (1)在spring配置文件中,使用bean标签,标签里面添加对应属性,就可以实现对象创建。
​ (2)在bean标签有很多属性,介绍常用的属性。
​ id属性:唯一标识。 class属性:类全路径(包类路径)。
​ (3) 创建对象时候,默认也是执行无参数构造方法完成对象创建。

②基于XML方式注入属性(DI)
1.set构造注入属性

创建属性实例 name和age

public class User {
    public String name;
    public Integer age;

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

    public void setAge(Integer age) {
        this.age = age;
    }

    public void add(){
        System.out.println("Hello World!");
    }
}

使用property进行属性注入

<?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">

    <!-- 配置User对象创建 -->
    <bean id="user" class="com.atguigu.spring5.User">
        <!-- set方法注入属性 -->
        <!-- 使用property完成属性注入
                name:类里面属性名称
                value:向属性注入的值
         -->
        <property name="age" value="13"></property>
        <property name="name" value="王兴华"></property>
    </bean>
</beans>

测试

//1.加载Spring配置文件
ApplicationContext context = new ClassPathXmlApplicationContext("bean01.xml");
//2.获取配置创建的对象
User user = context.getBean("user",User.class);

System.out.println(user.age + user.name);
user.add();
2.有参构造注入属性

创造有参实例name和age

package com.atguigu.spring5;

public class User {
    public String name;
    public Integer age;

    public User(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public void add(){
        System.out.println("Hello World!");
    }
}

使用constructor-arg完成有参构造注入

<?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">

    <!-- 配置User对象创建 -->
    <bean id="user" class="com.atguigu.spring5.User">
        <!-- 使用constructor-arg完成有参构造注入 -->
        <constructor-arg name="age" value="13"></constructor-arg>       <!-- 通过属性名称 -->
        <constructor-arg name="name" value="wxh"></constructor-arg>
        <constructor-arg index="0" value="wxh"></constructor-arg>       <!-- 也可以通过构造方法索引 -->
        <constructor-arg index="1" value="16"></constructor-arg>
    </bean>
</beans>
3.p名称空间注入(了解)

在这里插入图片描述

4.xml注入其他类型属性

1.字面量

注入null值

<!-- 向name属性注入null -->
<property name="name">
    <null/>
</property>

注入特殊符号

<!-- 第一种方式使用转义字符 &lt &gt 
     第二种方式使用<![CDATA[内容]]>  -->
<property name="name">
    <value><![CDATA[<<王兴华>>]]></value>
</property>
5.注入属性 -外部bean

创建两个类service类和dao类

package com.atguigu.spring5.service;

import com.atguigu.spring5.dao.UserDao;
import com.atguigu.spring5.dao.UserDaoImpl;

public class UserService {

    //创建UserDao类型属性,生成set方法
    private UserDao userDao;
    public void setUserDao(UserDao userDao){
        this.userDao = userDao;
    }

    public void add(){
        System.out.println("Service add..................");
//        //原始方式
//        UserDao userDao = new UserDaoImpl();
        userDao.update();
    }
}
package com.atguigu.spring5.dao;

public interface UserDao {
    public void update();
}


package com.atguigu.spring5.dao;

public class UserDaoImpl implements UserDao{
    @Override
    public void update() {
        System.out.println("dao update..............");
    }
}

在service调用dao里面的方法

这里要用ref属性

<?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">

    <!--  1 Service和dao对象创建 -->
    <bean id="userService" class="com.atguigu.spring5.service.UserService">
        <!-- 注入userDao对象
               name属性:类里面属性名称
               ref属性:创建userDao对象bean标签id值
               -->
        <property name="userDao" ref="userDaoImpl"></property>
    </bean>
    <bean id="userDaoImpl" class="com.atguigu.spring5.dao.UserDaoImpl"></bean>
</beans>

测试

public class SpringBean {
    @Test
    public void test01(){
        //1.加载Spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("bean02.xml");
        //2.获取配置创建的对象
        UserService userService = context.getBean("UserService", UserService.class);

        userService.add();
    }
}
6.注入属性- 内部bean和级联赋值

(1) 一对多关系:部门和员工。
一个部门有多个员工,一个员工属于一个部门。
部门是一,员工是多。
(2)在实体类之间表示一对多关系,员工表示所属部门,使用对象类型属性进行表示。

//部门类
public class Dept {
    private String dname;

    public void setDname(String dname) {
        this.dname = dname;
    }
}

//员工类
public class Emp {
    private String ename;
    private String gender;
    //员工属于某一个部门,使用对象形式表示
    private Dept dept;

    public void setDept(Dept dept){
        this.dept = dept;
    }

    public void setEname(String ename) {
        this.ename = ename;
    }

    public void setGender(String gender) {
        this.gender = gender;
    }
}

创建内部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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="emp" class="com.atguigu.spring5.bean.Emp">
        <property name="ename" value="lucy"></property>
        <property name="gender" value=""></property>

        <!-- 设置对象类型属性 -->
        <property name="dept">
            <bean id="dept" class="com.atguigu.spring5.bean.Dept">
                <property name="dname" value="保安部"></property>
            </bean>
        </property>
    </bean>
</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="emp" class="com.atguigu.spring5.bean.Emp">
        <property name="ename" value="lucy"></property>
        <property name="gender" value=""></property>
        <!-- 级联赋值 -->
        <property name="dept" ref="dept "></property>
    </bean>
    <bean id="dept" class="com.atguigu.spring5.bean.Dept">
        <property name="dname" value="财务部"></property>
    </bean>
</beans>

第二种级联赋值 !! !!但注意这种方法必须生成内部bean的get方法

<?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="emp" class="com.atguigu.spring5.bean.Emp">
        <property name="ename" value="lucy"></property>
        <property name="gender" value=""></property>

        <!-- 级联赋值 -->
        <property name="dept" ref="dept "></property>
        <property name="dept.dname" value="技术部"></property>
    </bean>
</beans>
7.XML注入集合类型
package com.atguigu.spring5.collectiontype;

import java.util.List;
import java.util.Map;
import java.util.Set;

public class Stu {
    //1.数组类型属性
    private String[] courses;

    //2.list集合类型属性
    private List<String> list;

    //3.map集合类型属性
    private Map<String,String> maps;

    //4.set集合类型属性
    private Set<String> sets;

    public void setCourses(String[] courses) {
        this.courses = courses;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setMaps(Map<String, String> maps) {
        this.maps = maps;
    }

    public void setSets(Set<String> sets) {
        this.sets = sets;
    }
}

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="Stu" class="com.atguigu.spring5.collectiontype.Stu">
        <!-- 数组注入 -->
        <property name="courses">
            <array>
                <value>java</value>
                <value>python</value>
                <value>Ruby</value>
                <value>C++</value>
            </array>
        </property>
        <!-- list注入 -->
        <property name="list">
            <list>
                <value>java</value>
                <value>python</value>
                <value>Ruby</value>
                <value>C++</value>
            </list>
        </property>
        <!-- map类型注入 -->
        <property name="maps">
            <map>
                <entry key="JAVA" value="java"></entry>
                <entry key="PYTHON" value="PYTHON"></entry>
                <entry key="RUBY" value="ruby"></entry>
            </map>
        </property>
        <!-- set类型注入 -->
        <property name="sets">
            <set>
                <value>java</value>
                <value>python</value>
                <value>Ruby</value>
                <value>C++</value>
            </set>
        </property>

    </bean>

</beans>

注入集合类型,但是集合为类集合(常用)

需要在外面创建类对象,之后在类内部使用ref标签导入

   <property name="courseList">
        <list>
            <ref bean="course01"></ref>
            <ref bean="course02"></ref>
        </list>
    </property>

</bean>

<!-- 创建多个course对象 -->
<bean id="course01" class="com.atguigu.spring5.collectiontype.Course">
    <property name="cname" value="Spring框架"></property>
</bean>
<bean id="course02" class="com.atguigu.spring5.collectiontype.Course">
    <property name="cname" value="Mybatis框架"></property>
</bean>
8.XML自动装配

根据指定装配规则(属性名称或者属性类型),Spring 自动将匹配的属性值进行注入。

创建Emp和Dept类

public class Emp {
    private Dept dept;

    public void setDept(Dept dept) {
        this.dept = dept;
    }

    @Override
    public String toString() {
        return "Emp{" +
                "dept=" + dept +
                '}';
    }
}

//==============================================
public class Dept {
    @Override
    public String toString() {
        return "Dept{}";
    }
}

(1)根据属性名称注入

<?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">

    <!-- 使用自动装配注入Dept对象 -->
    <!--bean标签属性autowire,配置自动装配
    autowire属性常用两个值:
        byName根据属性名称注入,注入值bean的id值和类属性名称一样
        byType根据属性类型注入
        -->
    <bean id="emp" class="com.atguigu.spring5.auto.Emp" autowire="byName">
<!--        <property name="dept" ref="dept"></property>-->
    </bean>

    <bean id="dept" class="com.atguigu.spring5.auto.Dept"></bean>
</beans>

(2)根据属性类型注入

<?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">

    <!-- 使用自动装配注入Dept对象 -->
    <!--bean标签属性autowire,配置自动装配
    autowire属性常用两个值:
        byName根据属性名称注入,注入值bean的id值和类属性名称一样
        byType根据属性类型注入
        -->
    <bean id="emp" class="com.atguigu.spring5.auto.Emp" autowire="byType">
<!--        <property name="dept" ref="dept"></property>-->
    </bean>

    <bean id="dept" class="com.atguigu.spring5.auto.Dept"></bean>
</beans>
9.外部属性文件

在这里插入图片描述

Bean管理

IOC操作Bean管理

1、Spring有两种类型bean,一种普通bean,另外一种工厂bean (FactoryBean)
2、普通bean:在配置文件中定义bean类型就是返回类型。
3、工厂bean:在配置文件定义bean类型可以和返回类型不一样。
第一步创建类,让这个类作为工厂bean, 实现接口FactoryBean兵实现接口里面的方法,在实现的方法中定义返回的bean类型

package com.atguigu.spring5.bean;

import org.springframework.beans.factory.FactoryBean;

public class FactoryBeanTest implements FactoryBean<Dept> {

    @Override
    public Dept getObject() throws Exception {
        Dept dept = new Dept();
        dept.setDname("lcl");
        return dept;
    }

    @Override
    public Class<?> getObjectType() {
        return null;
    }

    @Override
    public boolean isSingleton() {
        return FactoryBean.super.isSingleton();
    }
}

第二步实现配置文件。

<?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="mybean" class="com.atguigu.spring5.bean.FactoryBeanTest"></bean>
</beans>

第三部测试。

package com.atguigu.spring5.spirngTest;

import com.atguigu.spring5.bean.Dept;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class FactoryTest {
    public static void main(String[] args) {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("bean05.xml");

        //这里注意类为实现工厂类泛型的类
        Dept mybean = applicationContext.getBean("mybean", Dept.class);
        System.out.println(mybean.getDname());


    }
}

Bean的作用域

!!!在Spring里面,默认情况下,bean 是单实例对象

在这里插入图片描述

可以看到属于同一个对象

如何设置单实例还是多实例?

(1)在spring配置文件bean标签里面有属性(scope) 用于设置单实例还是多实例
(2) scope 属性值
第一个值默认值,singleton, 表示是单实例对象。
第二个值 prototype,表示是多实例对象。

<bean id="mybean" class="com.atguigu.spring5.bean.FactoryBeanTest" scope="prototype"></bean>

(3) singleton 和prototype区别
第一singleton 单实例,prototype 多实例。
第二设置scope值是singleton时候,加载spring配置文件时候就会创建单实例对象。设置scope值是prototype时候,不是在加载spring配置文件时候创建对象,在调用getBean方法时候创建多实例对象。

Bean生命周期

1、生命周期
(1)从对象创建到对象销毁的过程。
2、bean生命周期。
(1)通过构造器创建bean实例(无参数构造)
(2)为bean的属性设置值和对其他bean引用(调用set方法) 把bean实例传递bean后置处理器的方法postProcessBeforeInitializations
(3)调用bean的初始化的方法(需要进行配置初始化的方法) 把bean实例传递bean后置处理器的方法postProcessAfterInitializations
(4) bean可以使用了(对象获取到了)
(5)当容器关闭时候,调用bean的销毁的方法(需要进行配置销毁的方法)。

Bean管理注解方式

1、Spring 针对Bean管理中创建对象提供注解。
(1) @Component 普通组件
(2) @Service 控制层组件
(3) @Controller 业务层组件
(4) @Repository 持久层组件
上面四个注解功能是一样的,都可以用来创建bean实例,但通常用在不同层

基于注解实现对象创建

1.引入依赖

在这里插入图片描述

2.开启组件扫描

<?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"
       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">

    <!-- 开启组件扫描
        1如果扫描多个包,多个包使用逗号隔开
        2扫描包上层目录
        -->
    <context:component-scan base-package="com.atguigu"></context:component-scan>
</beans>

3.创建类,在类上面添加创建对象注解

package com.atguigu.spring5.service;

import org.springframework.stereotype.Component;

//在注解里面value属性值可以省略不写
//默认值是类名称,首字母小写
@Component(value = "empService")       //<bean id="empService" class=" "/>
public class EmpService {

    public void hello(){
        System.out.println("Hello World!");
    }
}

4.测试

public class SpringTest03 {
    public static void main(String[] args) {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean07.xml");

        EmpService empService = context.getBean("empService", EmpService.class);
        empService.hello();
    }
}

5.遇到问题

这里遇到bug nested exception is org.springframework.core.NestedIOException: ASM ClassReader failed to parse cla

解决办法:java1.8版本只支持spring4.0以上,需把pom里的sping版本换4.1.5就ok了,也可以把jdk调低点。

在这里插入图片描述

组件扫描配置细节

    <!-- 第一种 -->
    <!-- use-default-filters="false" 表示不使用默认的扫描方式
         include-filter  表示哪些内容被扫描
         type="annotation"  为注解扫描
         expression="org.springframework.stereotype.Controller" 表示只扫描Controller的注解
         -->
    <context:component-scan base-package="com.atguigu" use-default-filters="false">
        <context:include-filter type="annotation"
                                expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

    <!-- 第二种 -->
    <!-- exclude-filter 表示哪些内容不扫描 -->
    <context:component-scan base-package="com.atguigu">
        <context:exclude-filter type="annotation"
                                expression="org.springframework.stereotype.Controller"/>
    </context:component-scan>

</beans>

基于注解方式注入属性

(1) @AutoWired : 根据属性类型注入

第一步把service和dao对象创建,在service和dao类添加创建对象注解。

@Repository
public class UserDaoImpl implements UserDao{
    @Override
    public void update() {
        System.out.println("dao update..............");
    }
}
@Service
public class EmpService {
    
    public void hello(){
        System.out.println("Hello World!");
    }
}

第二步在service注入dao对象,在service类添加dao类型属性,在属性上面使用注解

@Service
public class EmpService {

    //不需要添加set方法
    @Autowired
    private UserDaoImpl userDao;

    public void hello(){
        System.out.println("Hello World!");
    }
}

(2) @Qualifier : 根据属性名称注入

这个 @Qualifier 注解的使用,和上面@AutoWired 一起使用

package com.atguigu.spring5.service;

import com.atguigu.spring5.dao.UserDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import org.springframework.stereotype.Service;

//在注解里面value属性值可以省略不写
//默认值是类名称,首字母小写
//@Component(value = "empService")       //<bean id="empService" class=" "/>
@Service
public class EmpService {

    //不需要添加set方法
    //如果有多个实现类就会出现找不到的情况就要使用@Qualifier和@Autowired配合使用
    @Autowired
    @Qualifier("userdao01")
    private UserDaoImpl userDao;

    public void hello(){
        System.out.println("Hello World!");
    }
}
package com.atguigu.spring5.dao;

import org.springframework.stereotype.Repository;

@Repository(value = "userdao01")
public class UserDaoImpl implements UserDao{
    @Override
    public void update() {
        System.out.println("dao update..............");
    }
}

(3) @Resource : 可以根据类型注入,可以根据名称注入

注意通常不使用这个,因为这个不是spring包里面的,而是javax包里的

//@Resource	 //根据类型进行注入 
@Resource(name = "userDaoImpl1") 		//根据名称进行注入 
private UserDao userDao;

(4) @Value : 注入普通类型属性

@Value(value = "abc")
private String name;

完全注解开发

创建类

@Service	//表示创建该bean对象
public class UserDaoImpl implements UserDao {
    @Override
    public void add() {
        System.out.println("add............");
    }
}
@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public void add(){
        System.out.println("Serivce add........");
        userDao.add();

    }
}

全局配置类(通过一个全局配置类替换xml配置)

package com.atguigu.spring5.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;

@Configuration  //作为配置类,代替xml文件
@ComponentScan(basePackages = {"com.atguigu"})  //扫描
public class SpringConfig {
}

测试类 注意有所不同

public class Test01 {

    @Test
    public void test01(){
        ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);

        UserService userService = applicationContext.getBean("userService", UserService.class);
        userService.add();
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值