spring IOC学习

IOC概念

控制反转(反转控制),将对象的创建以及相互之间的调用过程交给spring容器处理,以此达到降低代码间的耦合度的目的。

IOC底层原理

一、使用到的技术:xml解析,反射,工厂设计模式。
二、创建对象过程:
  1、创建xml配置文件,配置要创建的对象;
  2、解析xml配置文件,根据配置的信息创建对象,大致代码如下:

package entity;

public class ObjectFactory {
    public static Object getBean() throws ClassNotFoundException, IllegalAccessException, InstantiationException {
        //通过xml解析,得到bean标签里面的类的class属性值
        String classPath = "xxx";
        // 通过反射创建对象
        Class<?> clazz = Class.forName(classPath);
        //返回实例
        return (User) clazz.newInstance();
    }
}

IOC接口

一、IOC思想基于IOC容器完成,而IOC容器的底层是对象工厂。
二、spring为实现IOC提供了两种方式(两个接口):
  1、BeanFactory:IOC容器的基本实现,是spring内部实现的接口,不提供给开发人员使用。加载配置文件时不会创建对象,只有使用时才会创建对象
BeanFactory加载配置文件

  2、ApplicationContext:BeanFactory的一个子接口,提供了更多更强大的功能,一般由开发人员使用。加载配置文件时就会创建对象
Application加载配置文件

IOC操作Bean管理

一、Bean管理的概念
bean管理是指两个操作:创建对象、注入属性。
二、Bean管理的两种实现方式

1、基于xml配置方式实现

1.1、基于xml方式创建对象

创建User类,默认拥有无参构造

package entity;

public class User {
    private String name;
    private int age;
    private int sex;

    public void print() {
        System.out.println("hello world");
    }
}

配置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">

    <bean id="user1" class="entity.User"/>
</beans>

读取配置文件,创建对象

public class MyTest {
    @Test
    public void testCreate() {
        //加载配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        //获取配置创建对象
        User user1 = context.getBean("user1", User.class);
        user1.print();
    }
}

执行结果:
结果
1.2、基于xml方式注入属性
   DI:依赖注入(注入属性,IOC的一种具体实现)

set方法注入

set方法注入必须加上属性的set方法和空参构造(默认有空参构造),否则会报 BeanCreationException异常

package entity;

public class User {
    private String name;
    private int age;
    private int sex;
    
    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setSex(int sex) {
        this.sex = sex;
    }
    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                '}';
    }
}

配置属性注入

<?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="user1" class="entity.User">
        <!--使用property标签注入属性值,name:属性名,value:属性值-->
        <property name="name" value="dog"/>
        <property name="sex" value="1"/>
        <property name="age" value="10"/>
    </bean>
</beans>

读取配置文件,创建对象(下面几个例子将沿用这部分代码)

public class MyTest {
    @Test
    public void testCreate() {
        //加载配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        //获取配置创建对象
        User user1 = context.getBean("user1", User.class);
        System.out.println(user1);
    }
}

执行结果:
结果

有参构造注入

有参构造注入可以不用set方法,但是要加上有参构造方法,否则会报 BeanCreationException异常

package entity;

public class User {
    private String name;
    private int age;
    private int sex;

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

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                '}';
    }
}

配置属性注入

<?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="user1" class="entity.User">
        <!--第一种,根据属性名注入-->
        <!--<constructor-arg name="name" value="lion"></constructor-arg>
        <constructor-arg name="age" value="5"></constructor-arg>
        <constructor-arg name="sex" value="1"></constructor-arg>-->
        <!--第二种,根据属性顺序注入,下标从0开始-->
        <constructor-arg index="0" value="lion"></constructor-arg>
        <constructor-arg index="1" value="5"></constructor-arg>
        <constructor-arg index="2" value="1"></constructor-arg>
    </bean>
</beans>

执行结果
在这里插入图片描述

p命名空间注入

本质上还是set方法注入,所以可以不要有参构造,但是需要无参构造(默认有有参构造)和set方法,否则会报 BeanCreationException异常

package entity;

public class User {
    private String name;
    private int age;
    private int sex;

    public void setName(String name) {
        this.name = name;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public void setSex(int sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                '}';
    }
}

xml配置文件要引入p命名空间约束,否则会报XmlBeanDefinitionStoreException错误

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

    <bean id="user1" class="entity.User" p:name="tiger" p:age="8" p:sex="1">
    </bean>
</beans>

执行结果
p命名空间注入

c命名空间注入

本质上是有参构造注入,所以可以不需要set方法和空构造,但是要有有参构造,否则会报BeanCreationException异常

package entity;

public class User {
    private String name;
    private int age;
    private int sex;

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

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                '}';
    }
}

xml配置文件要加上c命名空间约束,否则会报XmlBeanDefinitionStoreException异常

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

    <bean id="user1" class="entity.User" c:name="cat" c:age="3" c:sex="1">
    </bean>
</beans>

执行结果
c命名空间注入

对象属性注入

如果属性类型是对象类型,如:数组,集合,则不能单纯使用value赋值,否则会报错
Pet类

package entity;

public class Pet {
    private String name;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public String toString() {
        return "Pet{" +
                "name='" + name + '\'' +
                '}';
    }
}

User类

package entity;

import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.Properties;

public class User {
    private String name;
    private int age;
    private int sex;
    private List<String> hobby;
    private String[] books;
    private Map<String, String> map;
    private Properties properties;
    private Pet pet;

    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public int getSex() {
        return sex;
    }
    public void setSex(int sex) {
        this.sex = sex;
    }
    public List<String> getHobby() {
        return hobby;
    }
    public void setHobby(List<String> hobby) {
        this.hobby = hobby;
    }
    public String[] getBooks() {
        return books;
    }
    public void setBooks(String[] books) {
        this.books = books;
    }
    public Map<String, String> getMap() {
        return map;
    }
    public void setMap(Map<String, String> map) {
        this.map = map;
    }
    public Properties getProperties() {
        return properties;
    }
    public void setProperties(Properties properties) {
        this.properties = properties;
    }
    public Pet getPet() {
        return pet;
    }
    public void setPet(Pet pet) {
        this.pet = pet;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", sex=" + sex +
                ", hobby=" + hobby + '\n' +
                ", books=" + Arrays.toString(books) + '\n' +
                ", map=" + map + '\n' +
                ", properties=" + properties + '\n' +
                ", pet=" + pet +
                '}';
    }
}

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

    <bean id="user1" class="entity.User">
        <property name="sex" value="1"/>
        <property name="age" value="20"/>
        <property name="name" value="fish"/>
        <property name="books">
            <array>
                <value>java从入门到放弃</value>
                <value>mysql从删库到跑路</value>
                <value>c语言从看懂到看开</value>
            </array>
        </property>
        <property name="hobby">
            <list>
                <value></value>
                <value></value>
                <value>rap</value>
                <value>篮球</value>
            </list>
        </property>
        <property name="map">
            <map>
                <entry key="k1" value="v1"/>
                <entry key="k2" value="v2"/>
                <entry key="k3" value="v3"/>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="url1">www.baidu.com</prop>
                <prop key="utl2">www.bilibili.com</prop>
            </props>
        </property>
        <property name="pet" ref="pet"/>
    </bean>
    <bean id="pet" class="entity.Pet">
        <property name="name" value="旺财"/>
    </bean>
</beans>

执行结果
对象属性注入

根据外部配置文件注入属性

引入mysql依赖和druid依赖(不是必须,只是这个例子使用了这两个依赖),在resource下创建jdbc.properrties配置文件
jdbc.properties

driver=com.mysql.cj.jdbc.Driver
url=jdbc:mysql://localhost:3306/course?serverTimezone=GMT%2B8&useSSL=false&useUnicode=true&characterEncoding=utf-8
user=root
password=123456

bean1.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">

	<!--加载配置文件-->
    <context:property-placeholder location="classpath:jdbc.properties"></context:property-placeholder>
    <bean id="datasource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${driver}"/>
        <property name="url" value="${url}"/>
        <property name="username" value="${user}"/>
        <property name="password" value="${password}"/>
    </bean>
</beans>

MyTest.java

import com.alibaba.druid.pool.DruidDataSource;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void testCreate() {
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        DruidDataSource source = context.getBean("datasource", DruidDataSource.class);
        System.out.println(
                source.getDriverClassName() + "\n" +
                source.getUrl() + "\n" +
                source.getUsername() + "\n" +
                source.getPassword() + "\n"
        );
    }
}

执行结果
在这里插入图片描述

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

    <bean id="user1" class="entity.User">
        <!--注入空值-->
        <property name="name">
            <null/>
        </property>
        <property name="age" value="6"/>
        <property name="sex" value="1"/>
    </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
        https://www.springframework.org/schema/beans/spring-beans.xsd">

    <bean id="user1" class="entity.User">
    	<!--转义生成特殊符号-->
    	<!--<property name="name" value="&lt;活着&gt;"></property>-->
    	
        <!--<![CDATA[属性值]]>-->
        <property name="name">
            <value><![CDATA[<活着>]]></value>
        </property>
        <property name="age" value="10"></property>
        <property name="sex" value="1"></property>
    </bean>
</beans>

执行结果
在这里插入图片描述

2、基于注解方式实现

2.1、spring对于bean管理对象的创建提供的注解:
(1)@Component
(2)@Repository:一般注解dao(持久)层
(3)@Service:一般注解service(业务)层
(4)@Controller:一般注解controller(web)层
上面四个注解无明确规定要放在哪一层,只是为了开发方便所以约定俗成,实际每一层都可以用随意的一种注解

2.2、基于注解方式创建对象
新建dao包,并且创建一个UserDao类
在这里插入图片描述

package dao;

import org.springframework.stereotype.Repository;
// 四个注解任意一个都可以:repository,service,controller,component
// 默认值是类名首字母小写,即userDao
@Repository("userDao")
public class UserDao {

    public void print() {
        System.out.println("hello world");
    }
}

配置xml配置文件,注意要加上context命名空间(引入component-scan标签)并引用模式文档(模式文档路径一定不能有误),否则会报XmlBeanDefinitionStoreException 异常

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

    <!--开启组件扫描base-package值为包路径,多个路径用“,”隔开或者扫描公共的上层目录-->
    <context:component-scan base-package="dao"></context:component-scan>
</beans>

_ 测试代码_

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

public class MyTest {
    @Test
    public void testCreate() {
        //加载配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        //获取配置创建对象
        UserDao dao = context.getBean("userDao", UserDao.class);
        dao.print();
    }
}

执行结果
在这里插入图片描述
2.3、基于注解方式注入属性
(1)@Autowired:根据属性类型自动装配
(2)@Qualifier:根据属性名称注入
(3)@Resource:可以根据属性类型注入,也可以根据属性名称注入(java自带的注解)
(4)@Value:注入普通类型属性

使用@Autowired注解和@qualifier注入

在dao包里面创建UserDao接口,并且创建UserDaoImpl类实现UserDao接口,使用@Repository注解,重写print方法

UserDao接口

package dao;

public interface UserDao {
    void print();
}

UserDaoImpl类

package dao;

import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl implements UserDao{

    @Override
    public void print() {
        System.out.println("hello userDaoImpl");
    }
}

创建service包,并且创建Service类,使用@Service注解,并且使用@Autowired注解注入UserDao属性

UserService类

package service;

import dao.UserDao;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class UserService{
    @Autowired
    private UserDao userDao;

    public void print() {
        System.out.println("hello service");
        userDao.print();
    }
}

修改bean1.xml配置文件,扫描dao和service包,如果扫描不全会报UnsatisfiedDependencyException(未扫描dao包)或者NoSuchBeanDefinitionException(未扫描service包)异常

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

    <!--开启组件扫描base-package值为包路径,多个路径用“,”隔开或者扫描公共的上层目录-->
    <context:component-scan base-package="dao,service"></context:component-scan>
</beans>

测试代码

import dao.UserDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.UserService;

public class MyTest {
    @Test
    public void testCreate() {
        //加载配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("bean1.xml");
        //获取配置创建对象
        UserService service = context.getBean("userService", UserService.class);
        service.print();
    }
}

执行结果
在这里插入图片描述
注意:在一个接口有多个实现时,可以使用 @Qualifier 确定要注入的类

UserDaoImpl2类

package dao;

import org.springframework.stereotype.Repository;

@Repository
public class UserDaoImpl2 implements UserDao{
    @Override
    public void print() {
        System.out.println("hello userDaoImpl2");
    }
}

UserService类

package service;

import dao.UserDao;
import dao.UserDaoImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;

@Service
public class UserService{
    @Autowired
    @Qualifier("userDaoImpl2")
    private UserDao userDao;

    public void print() {
        System.out.println("hello service");
        userDao.print();
    }
}

执行结果
在这里插入图片描述

使用@Resource注解注入

使用@Resource注解注入如果注入的接口只是单实现则可以根据类型注入

UserService

package service;

import dao.UserDao;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

@Service
public class UserService{
    // 根据类型注入
    @Resource
    private UserDao userDao;

    public void print() {
        System.out.println("hello service");
        userDao.print();
    }
}

使用@Resource注解注入如果注入的接口是多实现则可以根据名称注入

UserService

package service;

import dao.UserDao;
import org.springframework.stereotype.Service;
import javax.annotation.Resource;

@Service
public class UserService{
    // 根据名称注入
    @Resource(name = "userDaoImpl")
    private UserDao userDao;

    public void print() {
        System.out.println("hello service");
        userDao.print();
    }
}

执行结果
在这里插入图片描述

使用@Value注入普通属性

UserService

package service;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

@Service
public class UserService{
    @Value(value = "旺财")
    private String name;

    public void print() {
        System.out.println(name);
    }
}

执行结果
在这里插入图片描述

3、完全使用注解开发

新建config包,然后创建SpringConfig类
SpringConfig

package config;

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

@Configuration
@ComponentScan(basePackages = {"dao","service"})
public class SpringConfig{
}

创建测试类

import config.SpringConfig;
import dao.UserDao;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import service.UserService;

public class MyTest {
    @Test
    public void testConfig() {
        ApplicationContext context = new AnnotationConfigApplicationContext(SpringConfig.class);
        UserService service = context.getBean("userService", UserService.class);
        service.print();
    }
}

service等类使用根据 @Resource 根据名称注入的代码

执行结果
在这里插入图片描述

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值