Spring5------------IOC

一、通过配置文件创建类的对象

目录结构

 

 

 

User.java

package com.tang.spring;

public class User {
    public void add() {
        System.out.println("add");
    }
}

  

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

    <!--    配置User对象创建-->
    <bean id="user" class="com.tang.spring.User"></bean>
</beans>

  

测试类MyTest.java

package com.tang.spring.testdemo;

import com.tang.spring.User;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void testAdd() {
        //加载spring配置文件
        ApplicationContext context = new ClassPathXmlApplicationContext("bean.xml");
        //获取配置创建的对象
        User user = context.getBean("user",User.class);

        System.out.println(user);
        user.add();
    }
}

  

二、IOC容器

1、IOC底层原理

IOC(Inversion of Control):译为控制反转,把对象创建和对象之间的调用过程,交给Spring进行管理

目的:降低耦合度

IOC底层:工厂设计模式、xml解析、反射

我们可以把IOC容器的工作模式看做是工厂模式的升华,可以把IOC容器看作是一个工厂,这个工厂里要生产的对象都在配置文件中给出定义,然后利用编程语言的的反射编程,根据配置文件中给出的类名生成相应的对象。从实现来看,IOC是把以前在工厂方法里写死的对象生成代码,改变为由配置文件来定义,也就是把工厂和对象生成这两者独立分隔开来,目的就是提高灵活性和可维护性。

2、IOC接口(BeanFactory)

Spring提供IOC容器两种实现方式(两个接口):

BeanFactory:IOC容器基本实现,是Spring内部的使用接口,不推荐开发人员使用这种方式。加载配置文件的时候不会创建对象,使用对象的时候才去创建。

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

 

ApplicationContext主要实现类:

 

 

 

3、IOC操作:Bean管理

Bean管理指的是两个操作:

  1. Spring创建对象
  2. Spring注入属性

Bean管理有两种实现方式:

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

  bean标签常用属性:

    • id:bean的唯一标识,不能包含特殊字符
    • class:bean类的全路径(包名+类名)

  创建对象的时候,默认使用无参构造方法完成对象创建

 

  注入属性的两种方式:

    • 使用set方法注入属性
    • 使用有参构造器注入属性
package com.tang.spring;

public class User {
    private String name;

    public User() {
    }

    //使用有参构造器注入属性
    public User(String name) {
        this.name = name;
    }

    //使用set方法注入属性
    public void setName(String name) {
        this.name = name;
    }
}

  

<!--set方法注入属性
        Spring会通过反射调用set方法完成注入,故实体类中要写set方法
    -->
    <bean id="user" class="com.tang.spring.User">
        <!--使用property完成属性注入
            name:类里面的属性名字
            value:向属性注入的值
        -->
        <property name="name" value="唐三藏"></property>
     </bean>

  

<!--有参构造方法注入属性-->
    <bean id="user" class="com.tang.spring.User">
        <constructor-arg name="name" value="唐三藏"></constructor-arg>
     </bean>

  

注入外部bean

package com.tang.spring;

public class PrintUser {
    private User user01;

    public void setUser01(User user01) {
        this.user01 = user01;
    }

    public void print(){
        System.out.println(user01);
    }
}
<!--有参构造方法注入属性-->
    <bean id="user" class="com.tang.spring.User">
        <constructor-arg name="name" value="唐三藏"></constructor-arg>
     </bean>

    <bean id="printUser" class="com.tang.spring.PrintUser">
        <!--注入User对象
            name:属性名字,必须完全对应(属性名字和set方法名字要有一致性)
            ref:注入对象bean标签的id属性值
         -->
        <property name="user01" ref="user"></property>
    </bean>

  

注入内部bean

package com.tang.spring;

public class Dept {
    private String dname;

    public String getDname() {
        return dname;
    }

    public void setDname(String dname) {
        this.dname = dname;
    }
}
package com.tang.spring;

public class Empl {
    private String ename;
    private String gender;
    private Dept dept;

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

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

    public void add(){
        System.out.println(ename+"--"+dept);
    }
}
<bean id="empl" class="com.tang.spring.Empl">
        <!--设置两个普通属性-->
        <property name="ename" value="zhangsan"></property>
        <property name="gender" value="女"></property>
        <!--设置对象类型属性-->
        <property name="dept">
            <bean id="dept" class="com.tang.spring.Dept">
                <property name="dname" value="财务部"></property>
            </bean>
        </property>
     </bean>

  

注入集合类型

package com.tang.spring;

import java.util.List;

public class Course {
    private List<String> cname;

    public void setCname(List<String> cname) {
        this.cname = cname;
    }
}
package com.tang.spring;

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

public class Stu {
    private String[] courses;
    private List<String> list;
    private Map<String,String> map;
    private List<Course> courseList;

    public void setCourseList(List<Course> courseList) {
        this.courseList = courseList;
    }

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

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

    public void setMap(Map<String, String> map) {
        this.map = map;
    }
}

  

普通bean:在配置文件中定义的bean类型就是返回类型

工厂bean:在配置文件中定义的bean类型可以和返回类型不一样

 

创建工厂bean过程:

第一步:创建作为工厂bean的类(实现FactoryBean接口)

第二步:实现接口方法,在实现的方法中定义返回的bean类型

package com.tang.spring;

public class Course {
    private String cname;
    
    public void setCname(String cname) {
        this.cname = cname;
    }
    
    @Override
    public String toString() {
        return "Course{" +
                "cname='" + cname + '\'' +
                '}';
    }
}
package com.tang.spring;

import org.springframework.beans.factory.FactoryBean;

public class MyBean implements FactoryBean<Course> {
    //定义返回bean类型
    @Override
    public Course getObject() throws Exception {
        Course course = new Course();
        course.setCname("数据库");
        return course;
    }

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

    @Override
    public boolean isSingleton() {
        return false;
    }
}

  

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

scope属性值:

  • singleton(默认),表示是单实例对象,加载spring配置文件的时候就会创建单实例对象
  • prototype,表示是多实例对象,在调用getBean方法的时候创建多实例对象

 

自动装配(不常用)

bean标签属性autowire,配置自动装配

autowire属性值:

  • byName:根据属性名称注入
  • byType:根据属性类型注入

 

外部属性文件

直接配置连接池

<!--    直接配置连接池-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="com.mysql.cj.jdbc.Driver"></property>
        <property name="url" value="jdbc:mysql://localhost:3306/munumanage"></property>
        <property name="username" value="root"></property>
        <property name="password" value="admin"></property>
     </bean>

 

引入外部属性文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
                           http://www.springframework.org/schema/context  http://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="${mydata.driverClassName}"></property>
        <property name="url" value="${mydata.url}"></property>
        <property name="username" value="${mydata.username}"></property>
        <property name="password" value="${mydata.password}"></property>
    </bean>
</beans>

jdbc.properties

mydata.driverClassName=com.mysql.cj.jdbc.Driver
mydata.url=jdbc:mysql://localhost:3306/munumanage
mydata.username=root
mydata.password=admin

  

(2)基于注解方式实现

 使用注解目的:简化xml配置

 

Spring针对Bean管理中创建对象提供的注解:

  • @Component
  • @Service
  • @Controller
  • @Repository

上面四个注解功能是一样的,都可以用来创建bean实例

 

Spring针对Bean管理中属性注入提供的注解:

  • @Autowired:根据属性类型进行注入(byType)
  • @Qualifier:根据属性名称进行注入(byName)
  • @Resource:既可以根据属性类型注入,也可以根据属性名称注入
  • @Value:注入普通类型属性

注意:前三个是注入对象类型属性;使用@Qualifier注解,必须和@Autowired配套使用,不然会导致bean注入失败

 

第一步:引入依赖

 

第二步:开启组件扫描

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:context="http://www.springframework.org/schema/context"
       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
                           http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context.xsd">

    <!-- 开启组件扫描
         如果要扫描多个包,包之间用逗号隔开
    -->
    <context:component-scan base-package="com.tang.spring"></context:component-scan>
</beans> 

 

    <!-- 细节
         use-default-filters 表示不使用默认filter,自己配置filter
         context:include-filter 设置扫描哪些内容
         type="annotation" expression="org.springframework.stereotype.Component" 表示扫描@Component注解
    -->
    <context:component-scan base-package="com.tang.spring" use-default-filters="false">
        <context:include-filter type="annotation" expression="org.springframework.stereotype.Component"/>
    </context:component-scan>

    <!-- 细节
         使用默认filter
         context:exclude-filter 设置哪些内容不进行扫描
    -->
    <context:component-scan base-package="com.tang.spring">
        <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Component"/>
    </context:component-scan>

  

第三步:创建类,在类上面添加创建对象注解

package com.tang.spring;

import org.springframework.stereotype.Component;

//value属性可以省略不写,默认值为类名,首字母小写
@Component(value = "user")   // 和<bean id="user" class="com.tang.spring.User"></bean>作用一样
public class User {
    private String name;

    public User() {
    }

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

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

  

 第四步:属性注入

package com.tang.spring;

public interface UserDao {
    public void print();
}

  

package com.tang.spring;

import org.springframework.stereotype.Repository;

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

  

package com.tang.spring;

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

import javax.annotation.Resource;

@Service
public class UserService {

//不需要添加set方法
//@Resource 根据类型进行注入
//@Resource(name = "userDaoImplOne") 根据名称进行注入
@Autowired //根据属性类型进行注入
@Qualifier(value = "userDaoImplOne")
private UserDao userDao;

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

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

  

 完全注解开发

 配置类替代xml

package com.tang.spring;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.stereotype.Controller;

@Controller   //指定当前类作为配置类,替代xml文件
@ComponentScan(basePackages = {"com.tang.spring"})
public class MyConfig {
}

  

 测试类

package com.tang.spring.testdemo;

import com.tang.spring.*;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

public class MyTest {
    @Test
    public void testAdd() {
        //加载配置类
        ApplicationContext context = new AnnotationConfigApplicationContext(MyConfig.class);
        //获取配置创建的对象
        UserService userService = context.getBean("userService", UserService.class);

        userService.print();

    }
}

  

 

posted @ 2021-04-01 22:35  455994206  阅读(51)  评论(0)    收藏  举报