2.Spring-IoC

一.Ioc和DI

  1. IoC:Inverse of Control(控制反转):
    指将对象的创建权,反转给了Spring容器;

  2. DI:Dependency Injection(依赖注入):
    指Spring创建对象的过程中,将对象依赖属性(简单值,集合,对象)通过配置设值给该对象。

二.Hello World

步骤:

  1. 准备jar包
    1. spring-beans-4.2.4.RELEASE.jar
    2. spring-core-4.2.4.RELEASE.jar
    3. 报错再添加:
    4. commons.logging-1.2.jar
  2. 开发HelloWorld程序
  3. 在applicationContext.xml中完成配置(docs\spring-framework-reference\html\xsd-config.html)
  4. 启动容器
  5. 从容器中得到bean
  6. 调用bean响应的方法

HelloWorld类

@Setter@Getter@ToString
public class HelloWorld {
    private String name;
}

测试类App

public class App {
    //使用Spring的方式来创建对象和给对象属性赋值
    @Test
    public void Ioc() {
        //1:在classpath路径中找到applicationContext.xml配置文件
        Resource resource = new ClassPathResource("applicationContext.xml");
        //2:根据配置文件创建BeanFactory
        XmlBeanFactory factory = new XmlBeanFactory(resource);
        //3:从工厂中获取id为helloWorld的bean对象
        //方式1:getBean(String beanName)根据bean的id/name属性的值获取bean对象
        //HelloWorld world = (HelloWorld) factory.getBean("helloWorld");
        //方式2:getBean(Class<?> type)根据bean的类型来获取bean对象
        //HelloWorld world = factory.getBean(HelloWorld.class);
        //方式3:getBean("",HelloWorld.class)
        HelloWorld world = factory.getBean("helloWorld", HelloWorld.class);
        System.out.println(world);
    }
    //模拟Spring管理bean的原理
    @Test
    public void testMock() throws Exception {
        String className = "com.dusk._1_hello.HelloWorld";
        //反射
        Class<?> clz = Class.forName(className);
        //获取无参构造器
        Constructor<?> con = clz.getDeclaredConstructor();
        //可以访问私有变量
        con.setAccessible(true);
        Object obj = con.newInstance();
        //内省的方式个对象属性赋值
        PropertyDescriptor[] pds = Introspector.getBeanInfo(clz, Object.class).getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
            if(pd.getName().equals("name")){
                pd.getWriteMethod().invoke(obj,"真.西门吹.牛");
            }
        }
        HelloWorld world = (HelloWorld) obj;
        System.out.println(world);
    }
}

放在和类同一级目录文件下
HelloWorld.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">
<!--IoC:把bean交给Spring管理-->
<bean id="helloWorld" class="com.dusk._1_hello.HelloWorld">
    <!--DI:给对象的属性赋值-->
    <property name="name" value="真.红眼黑龙"/>
</bean>
</beans>

放在资源文件Resource下
applicationContext.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">
    <import resource="classpath:com/dusk/_1_hello/helloworld.xml"/>
</beans>

三.Spring基本配置

  1. 在Spring配置中,id和name属性都可以定义bean元素的名称,不同的是:
    id属性,遵守XML语法的ID约束(唯一)。必须以字母开始,可以使用字母、数字、连字符、下划线、句话、冒号,不能以“/”开头。

    1. name属性,就可以使用很多特殊字符,比如在Spring和Struts1或Spring
    2. MVC的整合中,就得使用name属性来的定义bean的名称。
    <bean name="/login" class="cn.wolfcode.pss.web.action.LoginAction" />
    

== 注意:从Spring3.1开始,id属性不再是ID类型了,而是String类型,也就是说id属性也可以使用“/”开头了,而bean元素的id的唯一性由容器负责检查。==

  1. 引入其他配置文件
    可以将一个applicationContext.xml文件分解成多个配置文件,然后在applicationContext.xml文件中包含其他配置文件即可。
    使用import元素引入其他的配置文件:
<import resource="classpath:cn/wolfcode/hello/hello.xml"/>

使用import元素注意:

  1. 默认情况下,从classpath的根路径寻找。
  2. 可以使用前缀来定位文件的基础位置:
  3. [classpath:]:后面的文件从classpath路径开始找(推荐);[注意classloader的问题。]
  4. [file:]:后面的文件使用文件系统的路径开始找;
    注意:只有当框架中实现了Resource接口才能够识别上述的前缀标识符。

四.Spring整合JUnit测试

Spring整合JUnit依赖jar:
Spring4.x需要依赖的单元测试得是最新的junit4.12,Eclipse3.7自带的junit4.8不支持,同时从Spring4.x开始,还得依赖AOP包的支持。

junit-4.12.jar
hamcrest-core-1.3.jar
spring-test-4.2.4.RELEASE.jar
spring-context-4.2.4.RELEASE.jar
spring-aop-4.2.4.RELEASE.jar
spring-expression-4.2.4.RELEASE.jar

若:
把@ContextConfiguration(“classpath:applicationContext.xml”) 写成@ContextConfiguration

默认去找的当前测试类名-context.xml配置文件,如:HelloWorldTest-context.xml

SpringTest类

//Spring整合JUnit测试框架
//RunWith表示容器直接运行在JUnti上,测试类运行在Spring容器中
@RunWith(SpringJUnit4ClassRunner.class)
//ContextConfiguration:告诉测试框架Spring配置文件的位置
@ContextConfiguration
public class SpringTest {
    //自动装配
    //表示在容器中找到对应的对象,自动注入过来
    @Autowired
    private HelloWorld world;
    @Test
    public void testOld(){
        //自己创建容器
        Resource resource = new ClassPathResource("applicationContext.xml");
        XmlBeanFactory factory = new XmlBeanFactory(resource);
        //从容器中取出对象
        HelloWorld world = factory.getBean("helloWorld", HelloWorld.class);
        System.out.println(world);
    }
    @Test
    public void testSpringTest(){
        //自己创建容器
        System.out.println(world);
    }

}

SpringTest-context.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">
    <!--IoC:把bean交给Spring管理-->
    <bean id="helloWorld" class="com.dusk._2_test.HelloWorld">
        <!--DI:给对象的属性赋值-->
        <property name="name" value="真.红眼黑龙"/>
    </bean>
</beans>

HelloWorld类

@Setter@Getter@ToString
public class HelloWorld {
    private String name;
}

五.IoC容器

IoC容器:BeanFactory和ApplicationContext对象
BeanFactory:是Spring中最底层的接口,只提供了最简单的IoC功能,负责配置,创建和管理bean。
在应用中,一般不使用BeanFactory,而推荐使用ApplicationContext(应用上下文),原因如下。
BeanFactory和ApplicationContext的区别:

  1. ApplicationContext继承了BeanFactory,拥有了基本的IoC功能;
  2. 除此之外,ApplicationContext还提供了以下的功能:
    1. 支持国际化;
    2. 支持消息机制;
    3. 支持统一的资源加载;
    4. 支持AOP功能;

container-context.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">
    <bean class="com.dusk._3_container.SomeBean" id="someBean">
        <property name="name" value="西门吹.牛"/>
    </bean>
</beans>

测试类SpringContainerTest

public class SpringContainerTest {

    //使用BeanFactory
    @Test
    public void testBeanFactory(){
        BeanFactory factory = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));
        System.out.println("-------------");
        SomeBean bean = factory.getBean("someBean", SomeBean.class);
        System.out.println(bean);
    }
    //使用ApplicationContext
    @Test
    public void testApplicationContext(){
        //参数1:文件名称,参数2:本类名称
        ApplicationContext ctx = new ClassPathXmlApplicationContext("App-Context.xml", SpringContainerTest.class);
        System.out.println("------");
        //参数1:配置id,参数2:bean字节码
        SomeBean bean = ctx.getBean("someBean", SomeBean.class);
        System.out.println(bean);
    }
}

实体类SomeBean

@Setter@ToString
public class SomeBean {
    private String name;
}

六.bean的实例化方式

bean的实例化方式:

  1. 构造器实例化(无参数构造器),最标准,使用最多。
  2. 静态工厂方法实例化:解决系统遗留问题
  3. 实例工厂方法实例化:解决系统遗留问题
  4. 实现FactoryBean接口实例化:实例工厂变种:
    集成其他框架使用:SqlSessionFactoryBean和MapperFactoryBean

App-Context.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">
    <!--&lt;!&ndash;方式四:实现FactoryBean接口的方式&ndash;&gt;
    <bean id="someBean" class="com.dusk._4_instance.instance_factory.SomeBeanFactoryBean"/>-->
    <!--方式三:实例工厂方法-->
    <bean id="factory" class="com.dusk._4_instance.instance_factory.SomeBeanFactory"/>
    <bean id="someBean" factory-bean="factory" factory-method="getObject"/>

   <!-- 方式二:使用静态工厂方法获取bean对象
    <bean id="someBean" class="com.dusk._4_instance.static_factory.SomeBeanFactory"
        factory-method="getObject"/>-->

    <!--&lt;!&ndash;方式1:使用bean的无参构造器来实例化对象&ndash;&gt;
    <bean id="someBean" class="com.dusk._4_instance.common.SomeBean">
        <property name="name" value="Dusk"/>
    </bean>-->
</beans>

SomeBean类

@Setter@Getter@ToString
public class SomeBean {
    public SomeBean(){
        System.out.println("SomeBean");
    }
    private String name;
}

方式一.构造器实例化

<bean id="someBean" class="com.dusk._4_instance.common.SomeBean">
        <property name="name" value="Dusk"/>
    </bean>

方式二.静态工厂方法实例化
SomeBeanFactory类

//静态工厂
public abstract class SomeBeanFactory {
    //获取Bean对象的方法是静态的
    public static SomeBean getObject(){
        System.out.println("静态复杂的初始化过程");
        return new SomeBean();
    }
}
<bean id="someBean" class="com.dusk._4_instance.static_factory.SomeBeanFactory"
        factory-method="getObject"/>

方式三.实例工厂方法实例化
SomeBeanFactory

//SomeBeanFactory对象的实例化
public class SomeBeanFactory {
    //获取Bean对象的方法不是静态的,需要改类的对象来调用
    public SomeBean getObject(){
        System.out.println("实例复杂的初始化过程");
        return new SomeBean();
    }
}
<bean id="factory" class="com.dusk._4_instance.instance_factory.SomeBeanFactory"/>
    <bean id="someBean" factory-bean="factory" factory-method="getObject"/>

方式四.实现FactoryBean接口实例化

public class SomeBeanFactoryBean implements FactoryBean<SomeBean>{
    //工厂方法
    public SomeBean getObject() throws Exception {
        System.out.println("实现接口复杂的初始化过程");
        return new SomeBean();
    }

    public Class<?> getObjectType() {
        return SomeBean.class;
    }

    public boolean isSingleton() {
        return true;
    }
}
<bean id="someBean" class="com.dusk._4_instance.instance_factory.SomeBeanFactoryBean"/>

测试类App

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class App {
    @Autowired
    private SomeBean someBean;
    //传统方式
    @Test
    public void testOld() {
        //1:找到静态工厂类
        //2:调用工厂中的静态方法
       /* SomeBean bean = SomeBeanFactory.getObject();
        System.out.println(bean);*/
    }
    @Test
    public void testStatic(){
        System.out.println(someBean);
    }

}

六.bean的作用域

<bean id="" class="" scope="作用域"/>

singleton: 单例 ,在Spring IoC容器中仅存在一个Bean实例 (默认的scope)
prototype: 多例 ,每次从容器中调用Bean时,都返回一个新的实例,即每次调用getBean()时 ,相当于执行new XxxBean():不会在容器启动时创建对象
request: 用于web开发,将Bean放入request范围 ,request.setAttribute("xxx") , 在同一个request获得同一个Bean
session: 用于web开发,将Bean 放入Session范围,在同一个Session 获得同一个Bean 
globalSession: 一般用于Porlet应用环境 , 分布式系统存在全局session概念(单点登录),如果不是porlet环境,globalSession 等同于Session  
	在开发中主要使用 scope="singleton"、 scope="prototype" 
      对于Struts2中的Action使用prototype类型,其他使用singleton
      Spring容器会管理Action对象的创建,此时把Action的作用域设置为prototype.

七.初始化和销毁

SomeBean类

public class SomeBean {
    private boolean flag;
    public SomeBean(){
        System.out.println("对象被创建");
    }
    public void init(){
        flag = true;
        System.out.println("对象初始化");
    }
    public void work(){
        if (!flag){
            throw new RuntimeException("对象未被初始化");
        }
        System.out.println("对象工作");
    }

    public void destroy(){
        System.out.println("对象被销毁");
    }
}

测试类App

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class App {
    @Autowired
    private ApplicationContext ctx;
    @Test
    public void test2(){
        SomeBean bean = ctx.getBean("someBean", SomeBean.class);
        bean.work();
    }
}

App-Context.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">
    <bean id="someBean" class="com.dusk._6_init_destroy.SomeBean"
        init-method="init" destroy-method="destroy"/>
</beans>

八.依赖注入

  1. 对象注入的方式:

    1. 自动装配(了解)
    2. 手动注入(重点)
    3. 注解注入(重点)
  2. 通过哪些手动可以注入:

    1. 可以通过属性注入(setter方法).
    2. 通过构造器注入.
    3. 通过SpEL注入.
  3. 注入的时候,可有注入哪些类型的值.

    1. 简单类型(单一的值,使用value属性).
    2. 复合类型(JavaBean类型,使用ref属性)
    3. 集合类型(多个值,使用对应的集合标签)
  4. 使用setter注入(属性注入):

    1. 使用bean元素的子元素设置;
      1. 简单类型值,直接使用value赋值;
      2. 复合类型,使用ref赋值;
      3. 集合类型,直接使用对应的集合类型元素即可。
    2. spring通过属性的setter方法注入值;
    3. 在配置文件中配置的值都是string,spring可以自动的完成类型的转换
    4. 属性的设置值是在init方法执行之前完成的
    5. 改进spring的测试,直接在测试类里面注入需要测试的对象

简单类型
EmployeeDAOImpl类

@ToString
public class EmployeeDAOImpl implements IEmployeeDAO{
    //简单类型
    @Setter
    private String dataSource;//模拟连接池
}
    <!--把DAO组件交给Spring管理-->
    <bean id="EmployeeDAO" class="com.dusk._7_di.dao.EmployeeDAOImpl">
        <!--DI:简单类型-->
        <property name="dataSource" value="druid"/>
    </bean>

集合类型
MyCollection

@Setter
public class MyCollection {
    private List<String> list;
    private String[] arr;
    private Set<String> set;
    private Map<String,Object> map;
    private Properties prop;

    public String toString() {
        return "MyCollection{" +
                "\nlist=" + list +
                ", \narr=" + Arrays.toString(arr) +
                ", \nset=" + set +
                ", \nmap=" + map +
                ", \nprop=" + prop +
                '}';
    }
}
 <!--属性注入:集合对象注入值-->
    <bean id="coll" class="com.dusk._7_di.list.MyCollection">
        <!--List集合注值-->
        <property name="list">
            <list>
                <value>list1</value>
                <value>list2</value>
            </list>
        </property>
        <!--对array注值-->
        <property name="arr">
            <array>
                <value>arr1</value>
                <value>arr2</value>
            </array>
        </property>
        <!--对Set注值-->
        <property name="set">
            <set>
                <value>set1</value>
                <value>set2</value>
            </set>
        </property>

        <!--对map集合注值-->
        <property name="map">
            <map>
                <entry key="k1" value="v1"/>
                <entry key="k2" value="v2"/>
            </map>
        </property>
        <property name="prop">
            <value>
                k1=v1
                k2=v2
            </value>
        </property>
    </bean>

构造器注入
Employee

//使用属性注入->简单类型
@Setter@Getter@ToString
public class Employee {
    private Long id;
    private String name;
    private BigDecimal salary;
    private URL url;
    private Class<?> clz;

    public Employee() {
    }

    public Employee(Long id, String name) {
        this.id = id;
        this.name = name;
    }
}
<!--构造器注值-->
<bean id="employeeC" class="com.dusk._7_di.Employee">
    <constructor-arg value="10" name="id"/>
    <constructor-arg name="name" value="Dusk"/>
</bean>

复合类型

EmployeeServiceImpl类

@ToString
public class EmployeeServiceImpl implements IEmloyeeService {
    //依赖一个DAO
    @Setter
    private IEmployeeDAO employeeDAO;//复合类型
}
<bean id="employeeService" class="com.dusk._7_di.service.EmployeeServiceImpl">
    <!--属性注入:复合类型,使用ref-->
    <property name="employeeDAO" ref="EmployeeDAO"/>
</bean>
<!--把DAO组件交给Spring管理-->
<bean id="EmployeeDAO" class="com.dusk._7_di.dao.EmployeeDAOImpl">
    <!--DI:简单类型-->
    <property name="dataSource" value="druid"/>
</bean>

九.property place holder(属性占位符)

没有联网的需要导入命名空间的约束文件

db.properties

jdbc.driverClassName=com.mysql.jdbc.Driver
jdbc.url=jdbc:mysql:///struts2
jdbc.username=root
jdbc.password=admin

app-context.xml

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

    <!--使用Spring来读取db.properties文件
        system-properties-mode忽略系统环境属性
        -->
    <context:property-placeholder location="classpath:db.properties" system-properties-mode="NEVER"/>
    <!--把Druid交给Spring来管理-->
    <bean id="dateSource" class="com.alibaba.druid.pool.DruidDataSource"
          init-method="init" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>

</beans>

测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration
public class App {
    @Autowired
    private DruidDataSource ds;
    @Test
    public void testDadaSource(){
        System.out.println(ds);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值