您的位置:首页 > 编程语言 > Java开发

Spring基础(IOC&DI)

2016-10-29 16:44 405 查看
Spring基础篇(IOC&DI)——导出自个人笔记


IOC控制反转:Inversion of Control
     将设计好的类交给系统(由软件系统控制,运行前,我完全不知道用到哪些类)去控制,而不是你的类内部控制。
DI依赖注入:是控制反转的具体实现,在运行期由容器将依赖关系注入到组件之中。

优点:
     


DI注入方式:
     
     1.Setter注入:通过属性的setXxx()方法进行注入 (bean、Array数组、List、Set、Map、Properties)
     2.构造器注入:通过类的构造方法进行注入
     3. 导入其他bean(引入外部Bean,内部引用Bean)
     4.工厂方法创建bean

1&2. Setter注入(最常见)  & Constructor注入

实体类:

package com.igeekhome.springreview.entity;

/**
 * 用户实体类
 *
 * Created by student on 2016/10/28.
 */
public class User {

    private int id;
    private String name;
    private String passwd;
    private String sex;

    public User() {
    }

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

    public int getId() {
        return id;
    }

    public void setId(int id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getPasswd() {
        return passwd;
    }

    public void setPasswd(String passwd) {
        this.passwd = passwd;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    @Override
    public String toString() {
        return "User{" +
                "id=" + id +
                ", name='" + name + '\'' +
                ", passwd='" + passwd + '\'' +
                ", 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
     http://www.springframework.org/schema/beans/spring-beans.xsd">

     <!--
           spring容器来: 实例化bean,同时注入一个值

           等同于
           com.igeekhome.springreview.entity.User  user = new com.igeekhome.springreview.entity.User();
           user.setId(1001);
           user.setName("zhengjinzhou");
           user.setPasswd("123456");
           user.setSex("男");
      -->

     <!--
     bean的作用域:
       singleton:  单例模式  (默认)  每次获取的都是相同的实例
          static     com.igeekhome.bean.HelloSpring  hello = new com.igeekhome.bean.HelloSpring();

       prototype:  原型模式 ,每次获取的都是不同的实例
     -->

     <bean id="user" class="com.igeekhome.springreview.entity.User" scope="prototype">
           <!-- 反射  public void setId(int id) -->
           <property name="id" value="1001"/>
           <property name="name" value="zhengjinzhou"/>
           <property name="passwd" value="123456"/>
           <property name="sex" value="男"/>
     </bean>

     <!-- 构造器方法注入
           默认情况是要按照实体类的构造器参数顺序类写constructor-arg
           我们可以利用index 或 name 来打乱顺序
      -->
     <bean id="user1" class="com.igeekhome.springreview.entity.User" scope="prototype">
           <constructor-arg index="1" name="name" value="feifei" />
           <constructor-arg index="0" name="id" value="1002" />
           <constructor-arg index="3" name="sex" value="女" />
           <constructor-arg index="2" name="passwd" value="123456" />
     </bean>
     
</beans>

测试:
     使用Spring提供的测试套件

package com.igeekhome.springreview;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.igeekhome.springreview.entity.User;

/**
 * 测试Setter注入和Constructor注入
 *         利用Spring提供的测试套件
 *
 * @author zheng
 *   2016年10月29日 上午10:37:08
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext.xml")
public class Review1Test {

     @Resource(name="user")
     private User user;

     @Resource(name="user1")
     private User user1;

     @Test
     public void testUser() {
           System.out.println(user);
           System.out.println(user1);
     }
}

可以在配置文件中导入其他配置文件,也可以在需要的地方导入多个配置文件

在配置文件中导入其他配置文件
-------------------------------------------------------------------------
    <!-- 导入外部的其他配置文件 -->
    <!-- <import resource="classpath:applicationContext2.xml"/>
    <import resource="classpath:applicationContext3.xml"/> -->
-------------------------------------------------------------------------
在需要的地方导入多个配置文件
-------------------------------------------------------------------------
//读取spring的配置文件
        ApplicationContext ctx =
                new ClassPathXmlApplicationContext("applicationContext.xml",
                        "applicationContext2.xml","applicationContext3.xml");

1&2. Array数组、List、Set、Map、Properties

实体:

//Array数组、List、Set
-----------------------------------------------------------------
package com.igeekhome.springreview.bean;

import java.util.Arrays;
import java.util.List;
import java.util.Set;

/**
 * 集合,数组注入
 *
 * @author zheng
 *    2016年10月24日 上午11:22:02
 */
public class CollectionImport {

    private String[] names;
    private List<String> passwds;
    private Set<String> hobbys;

    //通过setter方法来注入
    public void setNames(String[] names) {
        this.names = names;
    }
    public void setPasswds(List<String> passwds) {
        this.passwds = passwds;
    }
    public String[] getNames() {
        return names;
    }
    public List<String> getPasswds() {
        return passwds;
    }
    public Set<String> getHobbys() {
        return hobbys;
    }
    public void setHobbys(Set<String> hobbys) {
        this.hobbys = hobbys;
    }

    @Override
    public String toString() {
        return "CollectionImport [names=" + Arrays.toString(names) + ", passwds=" + passwds + ", hobbys=" + hobbys
                + "]";
    }

}
---------------------------------------------------------------
//Map
---------------------------------------------------------------
package com.igeekhome.springreview.bean;

import java.util.Map;

/**
 * Map注入
 *         键值对
 *
 * @author zheng
 *   2016年10月24日 上午11:35:06
 */
public class MapImport {

     private Map<String, String> map;

     public Map<String, String> getMap() {
           return map;
     }

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

     public void printMap(){
           System.out.println("键:"+map.keySet());
           System.out.println("值:"+map.values());
     }

}
----------------------------------------------------------------
//Properties

------------------------------------------------------------------
package com.igeekhome.springreview.bean;

import java.util.Properties;

/**
 * Properties注入:直属于Hashtable
 *   类似于Map,
 *
 * @author zheng
 *   2016年10月24日 上午11:45:24
 */
public class PropertiesImport {

     private Properties properties;

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

     public void printMap(){
           System.out.println("键:"+properties.keySet());
           System.out.println("值:"+properties.values());
     }

}

配置:

<?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
           array、 list、 set 通用的
     -->
     <bean id="collection" class="com.igeekhome.springreview.bean.CollectionImport">
           <!-- 数组 -->
           <property name="names">
                <array>
                     <value>北京</value>
                     <value>上海</value>
                     <value>南京</value>
                     <value>南京</value>
                </array>
           </property>
           <!-- List集合 -->
           <property name="passwds">
                <list>
                     <value>123</value>
                     <value>456</value>
                     <value>789</value>
                     <value>789</value>
                </list>
           </property>
           <!-- Set集合(会去重) -->
           <property name="hobbys">
                <set>
                     <value>游泳</value>
                     <value>起飞</value>
                     <value>打牌</value>
                     <value>打牌</value>
                </set>
           </property>
     </bean>

     <!-- Map注入 -->
     <bean id="map" class="com.igeekhome.springreview.bean.MapImport">
           <property name="map">
                <!-- 注入map -->
                <map>
                     <entry key="one" value="1" />
                     <entry key="two" value="2" />
                     <entry key="three" value="3" />
                     <entry key="three" value="4" />
                </map>
           </property>
     </bean>

     <!-- Properties注入 -->
     <bean id="properties" class="com.igeekhome.springreview.bean.PropertiesImport">
           <property name="properties">
                <props>
                     <prop key="prop1">prop1_value</prop>
                     <prop key="prop2">prop2_value</prop>
                     <prop key="prop3">prop3_value</prop>
                     <prop key="prop3">prop4_value</prop>
                </props>
           </property>

     </bean>

</beans>

测试:

package com.igeekhome.springreview;

import java.util.Arrays;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.igeekhome.springreview.bean.CollectionImport;
import com.igeekhome.springreview.bean.MapImport;
import com.igeekhome.springreview.bean.PropertiesImport;

/**
 * 测试数组,List集合,Set集合
 *         利用Spring提供的测试套件
 *
 * @author zheng
 *    2016年10月29日 上午10:37:08
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext2.xml")
public class Review2Test {

    //注入待测试数据集合实体对象
    @Resource(name="collection")
    private CollectionImport collection;

    //注入待测试数据Map实体对象
    @Resource(name="map")
    private MapImport map;

    //注入待测试数据Properties实体对象
    @Resource(name="properties")
    private PropertiesImport properties;

    @Test
    public void testCollection() {
        System.out.println("------------------测试数组与集合----------------------");
        System.out.println("数组:"+Arrays.toString(collection.getNames()));
        System.out.println("List集合:"+collection.getPasswds());
        System.out.println("Set集合:"+collection.getHobbys());
        System.out.println("Set集合,值唯一");
    }

    @Test
    public void testMap(){
        System.out.println("--------------------测试Map------------------------");
        map.printMap();
        System.out.println("键相等时,后者覆盖前者!");
    }

    @Test
    public void testProperties(){
        System.out.println("-------------------------测试Properties---------------------------");
        properties.printMap();
        System.out.println("键相等时,后者覆盖前者!");
    }

}

3.导入其他bean(引入外部Bean,内部引用Bean)

原理:先在配置文件中配置注入一个UserDao的实现类,然后将这个实现类注入到UserService实现类中。

UserDaoImpl:

package com.igeekhome.dao;

import java.util.ArrayList;
import java.util.List;

import com.igeekhome.entity.User;

/**
 * 用户Dao实现类
 *
 * @author zheng
 *    2016年10月24日 下午2:43:36
 */
public class UserDaoImpl implements UserDao{

    /** 查询所有用户 */
    @Override
    public List<User> findAllUsers() {

        List<User> users = new ArrayList<>();
        users.add(new User(1001, "郑锦洲1","123456"));
        users.add(new User(1002, "郑锦洲2","123456"));
        users.add(new User(1003, "郑锦洲3","123456"));
        users.add(new User(1004, "郑锦洲4","123456"));
        return users;
    }

}

UserServiceImpl:

package com.igeekhome.service;

import java.util.List;

import com.igeekhome.dao.UserDao;
import com.igeekhome.entity.User;

/**
 * 用户Service实现类
 *
 * @author zheng
 *    2016年10月24日 下午2:49:38
 */
public class UserServiceImpl implements UserService {

    //dao接口
    private UserDao userDao;

    //spring注入
    public void setUserDao(UserDao userDao){
        this.userDao = userDao;
    }

    /** 查询所有用户 */
    @Override
    public List<User> getAllUsers() {
        return userDao.findAllUsers();
    }

    /** 根据用户编号查询用户 */
    @Override
    public User findUserById(int id) {

        List<User> users = userDao.findAllUsers();
        User u = null;
        for(User user : users){
            if(user.getId() == id){
                u = user;
            }
        }
        return u;
    }

}

配置:

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

     <!-- dao -->
     <bean id="userDao" class="com.igeekhome.dao.UserDaoImpl"/>

     <!-- 业务类  
引入外部的Bean -->
     <bean id="userService" class="com.igeekhome.service.UserServiceImpl">
           <property name="userDao" ref="userDao"/>
     </bean>

     <!-- 内部引入Bean -->
     <bean id="userService1" class="com.igeekhome.service.UserServiceImpl">
           <property name="userDao">
                <bean class="com.igeekhome.dao.UserDaoImpl"/>

           </property>
     </bean>

</beans>

测试:

package com.igeekhome.loadbean;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.igeekhome.entity.User;
import com.igeekhome.service.UserService;

/**
 * @author zheng
 *    2016年10月24日 下午3:05:01
 */
public class LoadBean1Test {

    public static void main(String[] args) {

        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext6.xml");

        //UserService us = (UserService)ctx.getBean("userService");
        UserService us = (UserService)ctx.getBean("userService1");

        User user = us.findUserById(1002);

        System.out.println(user);
    }
}

4.工厂方法创建bean

构建工厂:

package com.igeekhome.springreview.factory;

import com.igeekhome.springreview.entity.User;

/**
 * 用户工厂类
 *         静态工厂方法
 *         实例工厂方法
 *
 * @author zheng
 *   2016年10月29日 上午11:37:30
 */
public class UserFactory {

     /**
      * 静态工厂方法
      * @return
      */
     public static User createUserByStaticFactory(){
           return new User(1001, "静态工厂生产", "123456", "男");
     }

     /**
      * 实例工厂方法
      * @return
      */
     public  User createUserByFactory(){
           return new User(1002, "实例工厂生产", "feifeifei", "男");
     }

}

配置:

<?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="user1" class="com.igeekhome.springreview.factory.UserFactory"

           factory-method="createUserByStaticFactory" />

     <!-- 实例工厂方法 -->
     <!-- 先有一个对应的工厂Bean -->
     <bean id="factory" class="com.igeekhome.springreview.factory.UserFactory" />
     <!-- 根据这个工厂bean 生成对应其生产的东西 -->
     <bean id="user2" factory-bean="factory" factory-method="createUserByFactory" />

</beans>

测试:

package com.igeekhome.springreview;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.igeekhome.springreview.entity.User;

/**
 * 测试工厂方法来构建Bean
 *         利用Spring提供的测试套件
 *         静态工厂
 *         实例工厂
 *
 * @author zheng
 *   2016年10月29日 上午10:37:08
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:applicationContext3.xml")
public class Review3Test {

     //注入由静态工厂构建的Bean
     @Resource(name="user1")
     private User user1;

     //注入由实例工厂构建的Bean
     @Resource(name="user2")
     private User user2;

     @Test
     public void testStaticFactory() {
           System.out.println("静态工厂构建:"+user1);
     }

     @Test
     public void testFactory(){
           System.out.println("实例工厂构建:"+user2);
     }

}

小扩展:

     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的生命周期方法   
    init-method
    destroy-method
    -->
    <bean id="user" class="com.igeekhome.entity.User"
    init-method="init" destroy-method="destory" />

</beans>

     
     Bean的作用域:
          
          singleton;     prototype;     request;     session



     

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

     <!-- 实例化UserDaoImpl 的 Bean -->
     <bean id="userDao" class="com.igeekhome.dao.UserDaoImpl" />
     <bean id="userDao1" class="com.igeekhome.dao.UserDaoImpl" />

     <!--
           自动装配

          类型
           - default
           - no
           - byName 所需依赖的属性名称和我已经设置装配的Bean的id字段匹配
           - byType 存在问题,如果当前项目的存在多个对应类型的实例Bean时,比如上面的userDao和userDao1,会存在问题,无法确定使用哪一个。
           - constructor
      -->

     <!-- 出现问题了!!!
     <bean id="userService" class="com.igeekhome.service.UserServiceImpl" autowire="byType" />
      -->

      <!-- 实例化UserServiceImpl 的Bean 并为其属性进行【自动装配】 -->
     <bean id="userService1" class="com.igeekhome.service.UserServiceImpl" autowire="byName" />

</beans>


测试:

package com.igeekhome.loadbean;

import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.igeekhome.entity.User;
import com.igeekhome.service.UserService;

/**
 * 自动装配测试
 * @author zheng
 *    2016年10月24日 下午3:05:01
 */
public class LoadBean4Test {

    public static void main(String[] args) {

        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext9.xml");

        //配置了 autowire="byType"
        //UserService userService = (UserService)ctx.getBean("userService");

        //配置了 autowire="byName"
        UserService userService = (UserService)ctx.getBean("userService1");

        User user = userService.findUserById(1002);

        System.out.println(user);
    }
}

重点:

注解的使用:
注解实现手动装配
注解实现自动装配

     配置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
     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.igeekhome" />

</beans>


     组件注解标签(每个被标注的类,都是一个组件,会被扫描到)
     
@Service : 用于标注业务层组件
@Controller :用于标注控制层组件(如SpringMVC中的控制器)
@Repository :用于标注数据访问组件,即DAO组件
@Component :泛指组件,当组件不好归类的时候,我们可以使用这个注解进行标注

装配注解:
Autowired : 可以标注在属性和setter方法上。

Autowired注解默认按类型进行装配(byType)

获取该注解标注的属性或setter方法参数的类型
以该类型为条件到Spring的容器(applicationContext.xml)中去查找bean的id节点的类型,找到以后,获取该节点对应的对象,利用反射直接为属性赋值。

Qualifier("name") :该注解以名字为条件查找依赖对象,如果不存在该名称的对象,抛出异常!        
     实例: 
          


Resource:可以标注在属性和setter方法上

如果没有直达name属性

获取该注解的属性名称,以该名称为条件到spring容器(applicationContext.xml)中去查找bean的id节点的值相等节点,找到以后,获取该节点对应的对象,利用反射直接赋值。如果没有找到,@Resource注解会再次按类型装配。

如果指定name属性 只能按名称装配

获取该注解标注的属性名称,如果不存在该名称,抛出异常.

Value:装配值     
     实例:
          



Required :适用于bean属性的setter方法

指示受影响的bean属性必须在配置时被填充在XML配置文件中,否则容器将抛出BeanInitalizationException异常。

     实例:
          
          


 
     
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: