Spring 配置IoC的三种方式

1,530 阅读6分钟

Spring

Spring是一个分层的轻量级Java开发框架,位于业务层,核心是控制反转(IoC)和面向切面(AOP)。

IoC技术将所有对象交给Spring统一管理。

IoC

控制反转(Inversion of Control,IoC),是面向对象编程中的一种设计原则,可以用来减低计算机代码之间的耦合度。将对象的创建、销毁权反转给Spring。

DI

依赖注入(Dependency Injection,DI),在Spring框架负责创建Bean对象时,动态地将依赖对象注入到Bean对象中。

Spring配置IoC的三种方式:

1. 加载配置文件+在配置文件applicationContext.xml中配置Bean标签管理

加载配置文件

// 方法一:使用Spring的工厂,加载类路径下的Spring配置文件
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml"); 
// 通过工厂获得类对象
UserService userService = (UserService) applicationContext.getBean("userService");
//方法二:注解方式使用Spring的工厂,加载类路径下的Spring配置文件
@ContextConfiguration(value = "classpath:applicationContext_test.xml") // 加载类路径下的配置文件
<!--方法三:web项目使用web.xml文件加载-->
<!--  配置spring的监听器,加载applicationContext.xml配置文件-->
  <listener>
    <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
  </listener>
  <!--  配置加载类路径的配置文件-->
  <context-param>
    <param-name>contextConfigLocation</param-name>
    <param-value>classpath:applicationContext.xml</param-value>
  </context-param>

Bean标签常用属性

id:Bean的名字,具有唯一性

name:用于指定Bean的别名

class:用于指定Bean的来源,即对应的类(全名)

scope:用于指定bean的模式。

    singleton:是单例模式,容器只创建一个对象,默认值
    prototype:为非单例模式,容器创建多个对象,但容器不会去逐个销毁
    request:web项目中spring创建一个bean对象,将对象存到request域中
    session: web项目中将对象存到session域中
    globalSession:web项目中,把对象放到globalSession域里面,应用在prolet环境,如果没有prolet环境那么globalSession相当于session

property:配置自动注入JavaBean的成员变量

autowire:配置Spring对象属性的默认装配方式。

    no:不启动自动装配,默认值
    byType:根据类型自动装配
    byName:根据名称自动装配,name未声明时则默认使用id值

init-method:Bean的初始化方法,当Bean被载入到容器的时候调用

destory-method:Bean的销毁方法,当Bean从容器中删除的时候调用,只在scope= singleton有效

lazy-init:用于指定Bean的初始化时间。值为true表示在初次调用时才会自动创建实例并初始化;值为false表示在IoC容器创建的时候就会完成创建和初始化,默认是false

实例化Bean对象的三种方式:

(1)默认是无参数的构造方法(最常用)

<bean id="us" class="cn.service.UserServiceImpl" />

(2)静态工厂实例化

package cn.demo1;
import cn.service.UserService; 
import cn.service.UserServiceImpl; 
public class StaticFactory { 
    public static UserService createUs(){  
        System.out.println("通过静态工厂的方式创建UserServiceImpl对象..."); 
      // 编写业务逻辑 权限校验 
       return new UserServiceImpl();
    } 
}

<bean id="us" class="cn.demo1.StaticFactory" factory‐method="createUs" />

(3)动态工厂实例化

package cn.demo1; 
import cn.service.UserService; 
import cn.service.UserServiceImpl; 
public class Dfactory { 
    public UserService createUs(){ 
        System.out.println("实例化工厂的方式..."); 
        return new UserServiceImpl(); 
    } 
}

<bean id="dfactory" class="cn.demo1.Dfactory" /> 
<bean id="us" factory‐bean="dfactory" factory‐method="createUs" />

配合Bean标签的DI依赖注入方式

(1)属性的set方法注入值

(2)属性构造方法注入值

    //依赖注入方法一:提供该属性的set方法,IOC容器底层就通过属性的set方法方式注入值
    private OrderDao orderDao;
    public void setOrderDao(OrderDao orderDao) {
        this.orderDao = orderDao;
    }
    
    //依赖注入方法二:构造方法依赖注入
     private String msg;
     private String age;
     public OrderServiceImpl(String msg, String age) {
        this.msg = msg;
        this.age = age;
    }

    
     <bean id="orderService" class="cn.service.OrderServiceImpl">
        <property name="orderDao" ref="orderDao"/>
        <constructor-arg name="msg" value="你好"/>
        <constructor-arg name="age" value="20"/>
    </bean>
    <bean id="orderDao" class="cn.service.OrderDaoImpl"></bean>

数组、容器、Properties 依赖注入举例:

package xy.service;

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

public class CollectionBean {

    private String[] strs;
    private List<String> list;
    private Map<String,String> map;
    private Properties properties;

    public void setStrs(String[] strs) {
        this.strs = strs;
    }

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

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

    public void setProperties(Properties properties) {
        this.properties = properties;
    }

    @Override
    public String toString() {
        return "CollectionBean{" +
                "strs=" + Arrays.toString(strs) +
                ", list=" + list +
                ", map=" + map +
                ", properties=" + properties +
                '}';
    }
}

<bean id="collectionBean" class="xy.service.CollectionBean">
        <property name="strs">
            <array>
                <value>美美</value>
                <value>明明</value>
            </array>
        </property>
        <property name="list">
            <list>
                <value>小新</value>
                <value>猫咪老师</value>
            </list>
        </property>
        <property name="map">
            <map>
                <entry key="a" value="小花"/>
                <entry key="b" value="小猫"/>
            </map>
        </property>
        <property name="properties">
            <props>
                <prop key="username">root</prop>
                <prop key="password">1234567</prop>
            </props>
        </property>
    </bean>

2.加载配置文件+注解扫描+注解

加载配置文件同上

在applicationContext.xml中开启注解扫描

    <context:component-scan base-package="cn"/><!--包名-->

IOC常用注解

@Component 普通的类

@Controller 表现层

@Service 业务层

@Repository 持久层

依赖注入常用注解

@Value 用于注入普通类型(String,int,double等类型)

@Autowired 默认按类型进行自动装配(引用类型)

@Qualifier 和@Autowired一起使用,强制使用名称注入

@Resource Java提供的注解,也被支持。使用name属性,按名称注入 对象生命周期(作用范围)注解

@Scope 生命周期注解,取值singleton(默认值,单实例)和prototype(多例) 初始化方法和销毁方法注解(了解)

@PostConstruct 相当于init-method

@PreDestroy 相当于destroy-method

举例

// 默认当前类名就是ID名称,首字母小写
@Component(value = "c")
// @Controller
// @Service(value = "c")
// @Repository(value = "c")
// @Scope(value = "singleton") // 默认值,单例的
// @Scope(value = "prototype") // 多例的
public class Car {
    // 注解注入值,属性set方法是可以省略不写的。
    // 只有一个属性,属性的名称是value,value是可以省略不写的
    @Value("别克")
    private String cname;
    @Value(value = "500000")
    private Double money;
    // 也不用提供set方法
    // 按类型自动装配的注解,和id名称没有关系
    @Autowired
    // 按id的名称注入,Qualifier不能单独使用,需要Autowired一起使用。
    // @Qualifier(value = "person")
    // @Resource Java提供的注解,按名称注入对象,属性名称是name
    // @Resource(name = "person")
    private Person person;

    /*** Car对象创建完成后,调用init方法进行初始化操作 */
    @PostConstruct
    public void init() {
        System.out.println("init...");
    }
}

@Component(value = "person")
public class Person {
    @Value("小明")
    private String pname;

    @Override
    public String toString() {
        return "Person{" + "pname='" + pname + '\'' + '}';
    }
}

//测试(包含加载配置文件)
public class Demo {
    @Test
    public void run1() {
        // 工厂
        ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext_anno.xml");
        // 获取对象
        Car car = (Car) ac.getBean("c");
        System.out.println(car);
    }
}

3.IoC纯注解方式(编写配置类)+加载配置类

需要编写配置类,替换掉applicationContext.xml配置文件

@Bean注解 只能写在方法上,表明使用此方法创建一个对象,对象创建完成保存到IOC容器中

@Configuration // 声明配置类2 
public class SpringConfig2 { 
}

// 声明当前类是配置类 
@Configuration 
// 扫描指定的包结构 
@ComponentScan(value = "cn.demo") 
// 引入新的配置类2 
@Import(value = {SpringConfig2.class})
public class SpringConfig {
    /**
     * 创建连接池对象,返回对象,把该方法创建后的对象存入到连接池中,使用@Bean注解解决 
            <!‐‐配置连接池对象‐‐> 
        <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> 
           <property name="driverClassName" value="com.mysql.jdbc.Driver" /> 
           <property name="url" value="jdbc:mysql:///mydb" /> 
           <property name="username" value="root" /> 
           <property name="password" value="123456" /> 
        </bean> 
     *
     * @return 
     */
    
    @Bean(name = "dataSource")
    public DataSource createDataSource() {
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql:///mydb");
        dataSource.setUsername("root");
        dataSource.setPassword("123456");
        return dataSource;
    }
    
}

并加载配置类

// 方法一:创建工厂,加载配置类 SpringConfig.class
ApplicationContext ac = new AnnotationConfigApplicationContext(SpringConfig.class);
// 获取到对象 
Customer customer = (Customer) ac.getBean("customer");
//方法二:Spring纯注解整合Junit注解方式
@RunWith(SpringJUnit4ClassRunner.class) 
// 加载配置类 
@ContextConfiguration(classes = SpringConfig.class) 
public class Demo { 
    // 按类型自动注入对象 
    @Autowired 
    private Customer customer; 
    /**
     * 测试 
     */ 
    @Test 
    public void run1(){ 
        customer.save(); 
    }
}