Spring IOC容器和DI依赖注入

1.1 IOC容器

Inversion of Control 控制反转容器。

作用: 解决对象创建以及管理问题。

 

解析:

传统关于对象创建:

User user = new User(); 自己控制对象的创建,自己声明变量管理对象引用。

IOC:

需要对象,自己不创建,交给IOC容器创建并管理,需要的时候从IOC容器中获取即可,这种情况就叫控制反转。

实现:

IOC容器 = ApplicationContext容器类 + bean.xml配置

 

1.2 DI 依赖注入

Dependency Injection 依赖注入。

创建对象处理依赖关系::就是指对象是被动接受依赖类而不是自己主动去找,换句话说就是指对象不是从容器中查找它依赖的类,而是在容器实例化对象的时候主动将它依赖的类注入给它。

User user = new User();

Address address = new Address();

user.setAddress(address);//依赖注入

 

2.1创建Bean的细节

<!-- 对象加入IOC容器 -->
    <!-- 细节1:
       id: 不能以数字开头,不能有特殊符号(符合java标识符的命名规则)
           在IOC容器中id是不能重复
       name:可以数字开头,可以有特殊符号。
            描述的时候可以重复,但是实际使用还是会报错。
            可以有多个,用逗号分隔
     -->
     <!-- 细节2:(单例/多例) 默认是单例
          scope="prototype" 表示多例,每次获取都创建新的对象
                 singleton  默认值,表示单例
      -->	
      <!-- 细节3: 声明周期
         init-method:指定一个初始化方法。对象创建成功之后调用。
         destroy-method: 指定一个销毁的方法。在IOC容器调用destroy()方法的时候调用,对单例对象才有效。
         lazy-init: 延时初始化。
                    对单例对象有效,多例对象时无效。 
                    单例对象默认在IOC容器创建的时候就创建出来。
                    多例对象在获取对象的时候才去创建。
                    如果希望在对象创建的时候不直接创建单例对象,而是在第一次使用单例对象的时候创建,就可以设置延时初始化 
       --> 
    <bean id="user" lazy-init="true" class="com.xinboedu.test2.User" 
                scope="singleton" init-method="init" destroy-method="destroy"/>

 

2.2 创建对象的几种方式

创建对象的几种方式 : 

1) 调用无参数的构造方法

2) 调用有参数的构造方法,并通过构造方法赋值

3) 工厂模式( 静态工厂, 非静态工厂 )

4) 反射机制 (Spring IOC 原理就是反射机制)

class User {

    private String name;
    private int age;

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

    public User() {
        System.out.println("User被创建了!");
    }

    public void init() {
        System.out.println("初始化方法~");
    }

    public void destroy() {
        System.out.println("销毁的方法~");
    }

    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;
    }

    @Override
    public String toString() {
        return "User [name=" + name + ", age=" + age + "]";
    }
}
/
class UserFactory {
    //非静态
    public User getInstace() {
        User user = new User();
        user.setName("Jack");
        user.setAge(20);
        return user;
    }
    //静态
    public static User getStaticInstace() {
        User user = new User();
        user.setName("Jack");
        user.setAge(20);
        return user;
    }
    public static User getStaticInstace(String name, int age) {
        User user = new User();
        user.setName(name);
        user.setAge(age);
        return user;
    }
}
<!-- 1) 调用无参数的构造方法 -->
<bean id="user" class="com.xinboedu.test2.User"></bean>

<!-- 2) 调用有参数的构造方法 -->
<!--
        constructor-arg:构造方法赋值参数
        index: 赋值索引.不写的话按照默认顺序
        type:说明参数类型。
        value:要赋值的内容。字符串,会自动根据类型转换
        ref: 应用容器中现有对象赋值
-->
<!-- String str = new String("Lynn") -->
<bean id="str" class="java.lang.String">
    <constructor-arg value="Lynn"></constructor-arg>
</bean>
<bean id="user1" class="com.xinboedu.test2.User">
    <constructor-arg index="0" type="String" ref="str"> </constructor-arg>
    <constructor-arg index="1" type="int" value="18"> </constructor-arg>
</bean> -->

<!-- 3) 工厂模式 -->
<!-- 静态工厂: 不需要创建工厂对象 -->
<bean id="user2" class="com.xinboedu.test2.UserFactory" factory-method="getStaticInstace"></bean>

<!-- 非静态工厂:前提:有工程实例 -->
<bean id="userFactory" class="com.xinboedu.test2.UserFactory"></bean>
<bean id="user3" factory-bean="userFactory" factory-method="getInstace"></bean>

<!-- 指定参数的工厂 (相当于调用构造方法) -->
<bean id="user4" class="com.xinboedu.test2.UserFactory" factory-method="getStaticInstace">
    <constructor-arg index="0" type="String" value="Lynn"> </constructor-arg>
    <constructor-arg index="1" type="int" value="18"> </constructor-arg>
</bean>

 

/*反射机制*/

class App {
    public static void main(String[] args) {
        ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("root-context.xml");

        AccountService accountService = context.getBean(AccountService.class);

        System.out.println(accountService.sayHello());

        context.close();
    }
}

class App {
    public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException,
            InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {
        ClassLoader classLoader = Thread.currentThread().getContextClassLoader();

        Class clazz = classLoader.loadClass("me.laiyijie.demo.service.AccountService");

        Constructor constructor = clazz.getConstructor();

        AccountService accountService = (AccountService) constructor.newInstance();

        System.out.println(accountService.sayHello());
    }
}

 

2.3 处理对象的依赖关系

给对象属性赋值(DI,依赖注入),几种方式:

1) 构造方法赋值

2) setter方法注入

3) 内部bean写法

4) p名称空间

5) 自动装配

6) 注解方式

<!-- 方式一: setter方法 -->
<bean id="userDao" class="com.xinboedu.test1.UserDao"></bean>
<bean id="userService" class="com.xinboedu.test1.UserService">
    <property name="userDao" ref="userDao"></property>
</bean>
<bean id="userAction" class="com.xinboedu.test1.UserAction" scope="prototype">
    <property name="userService" ref="userService"></property>
</bean>

<!-- 方式二: 内部bean  -->
<!--
        内部bean设置id外部也引用不了
        外部bean是单例的话内部bean也是单例,外部多例,内部也多例
-->
<bean id="userAction" class="com.xinboedu.test1.UserAction" scope="prototype">
    <property name="userService">
        <bean class="com.xinboedu.test1.UserService">
            <property name="userDao">
                <bean class="com.xinboedu.test1.UserDao"></bean>
            </property>
        </bean>
    </property>
</bean>

<!-- 方式三: p名称空间 -->
<!-- 前提: 在xml最上方加入p名称空间 -->
<bean id="userDao" class="com.xinboedu.test1.UserDao"></bean>
<bean id="userService" class="com.xinboedu.test1.UserService" p:userDao-ref="userDao"></bean>
<bean id="userAction" class="com.xinboedu.test1.UserAction" p:userService-ref="userService" scope="prototype"></bean>

<!-- 方式四: 自动转配 -->
<!--
        (1)配置在指定的bean节点
        autowire="byName"  根据名称在IOC容器中查询对应的名称赋值给当前对象的对应的setter()方法
        byType  根据类型。 如果IOC容器中有两个同种类型的对象的话也报错。
        (2)配置到整个xml文件
        default-autowire="byType"	xml中所有的bean节点都自动转配
-->
<bean id="userDao" class="com.xinboedu.test1.UserDao"></bean>
<bean id="userService" class="com.xinboedu.test1.UserService" ></bean>
<!--  <bean id="userAction" class="com.xinboedu.test1.UserAction" autowire="byType" scope="prototype"></bean> -->
<bean id="userAction" class="com.xinboedu.test1.UserAction" scope="prototype"></bean>

<!-- 方式五: 注解方式 -->
<!-- (1) context 名称空间 -->
<!-- (2) 开启注解扫描 (如果有多个包,号分隔) -->
<context:component-scan base-package="com.xinboedu.test1"></context:component-scan>

 

 

========================================================================

附:

list, set, map和props元素分别用来设置类型为List,Set,Map和Propertis的属性值。分别用来为bean传入集合值。
 对应的spring的配置文件举例如下:

public   class  Chinese  implements  People   ...{   
     private String name;
	 private int age;
     private  List friends  =   new  ArrayList();   
     private  Map score  =   new  HashMap();   
     private  Properties basicInfo  =   new  Properties();   
     private  Set interest  =   new  HashSet();   
     // 省略对应set方法    
     .   
}  
<? xml version="1.0" encoding="gb2312" ?>    
 <! DOCTYPE beans PUBLIC "-//SPRING//DTD BEAN//EN"   
 "http://www.springframework.org/dtd/spring-beans.dtd" >    
    
 < beans >      
  < bean  id ="chinese"  class ="Chinese" >  
    <property name="name" value="123"></property>
   	<property name="age" value="18"></property>  
    <property  name ="friends" >    
             < list >    
                 < value > 张三 </ value >    
                 < value > 李四 </ value >    
                 < value > 王五 </ value >    
             </ list >    
    </property >    
    <property  name ="score" >    
             < map >    
                 < entry  key ="数学" >    
                     < value > 60 </ value >    
                 </ entry >    
                 < entry  key ="英语" >    
                     < value > 70 </ value >    
                 </ entry >    
                 < entry  key ="语文" >    
                     < value > 80 </ value >    
                 </ entry >    
                 < entry  key ="物理" >    
                     < value > 90 </ value >    
                 </ entry >    
                 < entry  key ="化学" >    
                     < value > 95 </ value >    
                 </ entry >    
             </ map >    
    </property >    
    <property  name ="basicInfo" >    
             < props >    
                 < prop  key ="身高" > 165 </ prop >    
                 < prop  key ="体重" > 45kg </ prop >    
                 < prop  key ="学历" > 大学本科 </ prop >    
             </ props >    
    </property >    
    <property  name ="interest" >    
             < set >    
                 < value > 唱歌 </ value >    
                 < value > 跳舞 </ value >    
                 < value > 书法 </ value >    
             </ set >    
    </property >     
   </bean >    
  </beans >    

 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值