Spring-IOC

Spring-----IOC

Spring 的作用及优势:用于整合,好处是解耦,降低组件不组件之间的关联,改善程序结构,便于系统的维护和扩展(使用 IoC 整合组件(各种 Bean),使用 AOP 来管理事务
Hibernate 、Spring 的使用没有限制,可以用于 Web 工程和普通 Java 程序

IOC:在类和类之间存在控制权,控制权指的是对象的创建和使用,之前的做法是在 A 中调用 B,那么控制权就在 A 中,引入 Spring 框架后,控制权由 spring 容器来负责。当 A 想使用 B 时,需要由 Spirng 容器通过配置文件进行注入。
AOP :通过预编译方式和运行期动态代理实现在不修改源代码的前提下给程序动态统一添加功能的一种技术(Struts2 中的拦截器,就是使用 AOP 的思想)

 

 

spring框架(web应用中)的实例化    (加载 Spring 配置文件创建 Spring 容器):
 ---自动创建:(随web的应用的启动而自动创建并加载配置初始化
   方式一:直接在web.xml文件中配置ContextLoadListener实例化spring容器

    有如下两种方法:
       1.利用ServletContextListener实现
       2.采用load-on-startup Servlet实现 (暂无)

 ServletContextListener实现方式、操作及说明:
 spring提供ServletContextListener的一个实现类ContextLoadListener,该类可以作为Listener使用,会在创建时自动查找web-inf/applicationContext.xml文件,
 如果只有一个配置文件,并且名为applicationContext.xml,只需要在web.xml文件中加入如下配置即可:
  <listener> 
       <listener-class>  org.springframework.web.context.ContextLoaderLister  </listener-class> 
  </listener> 
 如果有多个配置文件需要载入,则考虑用<context-param>元素来确定配置文件的文件名。ContextLoadListenter加载时,会查找名为contextConfigLocation的参数,配置context-param时参数名应该是contextConfigLocation
  <context-param> 
     <param-name> contextConfigLocation </param-name>
     <param-value> /WEB-INF/actionContext.xml,/WEB-INF/appContext.xml,/WEB-INF/daoContext.xml </param-value>  <!-- 配置多个文件之间,以","隔开 --> 

  </context-param>

  <listener> 
       <listener-class>  org.springframework.web.context.ContextLoaderLister  </listener-class>  <!-- 采用listener创建ApplicationContext实例 --> 

  </listener>
 如果没有通过contextConfigLocation指定配置文件,spring会自动查找applicationContext.xml文件;如果有contextConfigLocation,则利用该参数确定的配置文件,如果无法找到合适的配置文件,spring将无法正常初始化
     spring根据bean定义创建WebApplicationContext对象,并将其保存在web应用的ServletContext中。大部分情况下,应用的Bean无须感受到ApplicationContext的存在,只要利用ApplicationContext的IOC容器
 如果需要在应用中获取ApplicationContext实例,可以通过如下代码获取
 WebApplicationContext ctx=WebApplicationContextUtils.getWebApplicationContext(ServletContext);//获取当前web应用的spring的容器

 

    方式二:利用第三方MVC框架的扩展点,创建spring容器  (在struts配置文件struts-config.xml中配置)
      Struts有一个扩展点PlugIn,spring正是利用了PlugIn这个扩展点,从而提供了与Struts的整合。spring提供了PlugIn的实现类org.springframework.web.struts.ContextLoadPlugIn,这个实现类可作为struts的PlugIn配置,
Struts框架启动时,将自动创建Spring容器
     为了利用struts的PlugIn创建Spring容器,只需要在struts配置文件struts-config.xml中增加如下片段即可
  <plug-in className="org.springframework.web.struts.ContextLoaderPlugIn">
     <set-property property="contextConfigLocation" value="/WEB-INF/actionContext.xml,/WEB-INF/appContext.xml,/WEB-INF/daoContext.xml" />
  </plug-in>
      其中,指定contextConfigLocation属性值时,即可以指定一个spring配置文件的位置,可以指定多个spring配置文件的位置

 ---手动创建:
  方式一:
     1)配置文件在根目录下
     String[] CONFIGS = {"king/demo3/applicationContext.xml"};
     Resource  resource = new ClassPathResource(CONFIGS);
     BeanFactory  ac = new XmlBeanFactory(resource);
            UseBean  bean = (UseBean) ac.getBean("组件id");
  
     2)配置文件在其他任一位置
     Resource  resource = new FileSystemResource("D:/.../applicationContext.xml");
     BeanFactory  ac = new XmlBeanFactory(resource);
     UseBean  bean = (UseBean) ac.getBean("组件id");

  方式二:推荐方式(上面的子类)
     1)ApplicationContext  ac = new ClassPathXmlApplicationContext("项目/根目录/applicationContext.xml");实例化spring容器
        UseBean  bean = (UseBean) ac.getBean("组件id");实例化容器中的组件
        ac.close();关闭spring容器
  
     2)ApplicationContext  ac = new FileSystemXmlApplicationContext("D:/.../applicationContext.xml");引入项目外的配置文件实例化spring

 

Spring容器通过配置自动实例化 和手动实例化对比:

private LogFacade logFacade;        //属性(setter方法省略)

 

logFacade.operateLog();//spring容器通过web.xml中配置的监听器随web容器启动而启动,组件的实例化和注入装配由spring容器控制

 

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");//手动实例化spring容器
bean= (LogFacade)ac.getBean("该类的bean id");                                                           //手动实例化组件

bean.logFacade.operateLog();                                //调用实例化组件属性(属性注入由xml配置)的方法

 

Spring容器中的组件实例化:(spring框架就像是工厂类)
组件不需要 new 实例化对象,将需要调用的组件 HelloBean(接口类型) 声明为自己的属性,实例化对象在配置文件中迚行配置由 spring 框架完成(在配置文件中,通过<property>标签的配置,将属性通过属性注入的方式注入到具体的实例化对象组件中)

组件创建时机
1、默认情况下 组件对象 在 Spring 容器被创建时就会被创建
2、<bean id="mybean" lazy-init="true" class="demo3.MyBean"></bean> 
   lazy-init="true"组件实例化被推迟(不随容器创建而创建)
   lazy-init="false"当调用(使用)组件 时,组件才被实例化
3、让所有的 bean 都延迟创建(可以批量指定延迟加载 bean):<beans ... default-lazy-init="false">

组件创建模式
1、默认情况下 Spring 容器是通过单例模式(每次调用组件都是同一个)创建 Bean 对象-----有多线程并发访问的风险
2、<bean id="mybean" lazy-init="true" scope="prototype" class="demo3.MyBean"></bean> 原型模式(prototype):每次调用组件都创建新的

组件初始化
<bean id="mybean" init-method="myinit" class="demo3.MyBean"></bean> init-method 属性用于bean 对象创建后自动调用指定的初始化方法

组件销毁
destroy-method 属性用于指定销毁方法(仅适用于 singleton 模式)

 

 

spring框架---IOC技术:
IoC 是由 Spring 容器来完成的,Spring 容器通过依赖注入 DI 建立起对象(组件、Bean)之间的关系。
在 bean 对象 A 中使用 bean 对象 B,我们把B作为A的一个属性写在类A中:
public class B{

}
public class A{
   private B b =new B();
}
缺点:A和B的耦合度太高

 

用接口降低耦合度
public interface IB{ 
}
public class B implements IB{  
}

public class A{
   private IB b =new B();
}

用接口+工厂降低耦合度

public interface IB{ 
}
public class B implements IB{  
}

public class Factory{
   puclic static String getInstance(){return new B();}
}

public class A{
   private IB b =Factory.getInstance();
}

用Spring的IOC降低耦合度

IOC的DI注入:(分:手动装配和自动装配

手动装配:

public interface IB{
}
public class B implements IB{ 
}

public class A{
   private IB b;   //接口类型
   private String name;
   private List<String> city;  //集合
   private Set<String> na;
   private Map<String,Object> books;
   private Properties params;
  
   public void setB(IB b){this.b=b;}                                          //setter方式注入

   public void setParams(Properties params) {this.params = params;}
   public void setBooks(Map<String, Object> books) {this.books = books;}
   public void setNa(Set<String> na) {this.na = na;}
   public void setCity(List<String> city) {this.city = city;}

   public A(IB b,String name){this.b=b;this.name=name;}  //构造方式注入
}

applicationContext.xml:

<bean id="a"  class="A">
   <property  name="b" ref="bb"></property>   //setter方式注入属性(接口属性和具体类的关系----是工厂类的替代)
   <property  name="name"     value="张三"></property>  //setter方式注入属性

   <property name="city">     //通过setter方式注入属性,并赋值(通常在类A中赋值)
       <list>
            <value>北京</value>
             <value>上海</value>
            <value>深圳</value>
       </list>
   </property>
   <property name="na">
       <set>
            <value>tom</value>
            <value>jack</value>
            <value>rose</value>
       </set>
   </property>
   <property name="books">
       <map>
           <entry key="ISBN001" value="Struts框架开发"></entry>
           <entry key="ISBN002" value="Hibernate框架开发"></entry>
           <entry key="ISBN003" value="Spring框架开发"></entry>
       </map>
   </property>
   <property name="params">
       <props>
           <prop key="username">root</prop>
           <prop key="password">root</prop>
           <prop key="driverClass">com.mysql.jdbc.Driver</prop>
           <prop key="url">jdbc:mysql://localhost:3306/test</prop>
       </props>
   </property>

   <constructor-arg  index="0"  ref="b"></constructor-arg>           //构造方式注入属性b
   <constructor-arg  index="1"  value="张三"></constructor-arg> //构造方式注入属性name
</bean>

 

<bean id="bb"  class="B"></bean>

 手动装配:通过在“A”这个bean中用ref属性引用“bb”这个bean

 自动装配:(分xml-based和annotation-based(即注解)两种方式)

基于xml-based配置方式的自动装配:

只是不需要了id=”a“的<bean>的properties子元素,而加上一个autowire属性(单个bean配置装配类型):

 

<bean id="a" class="A"  autowire="byType"></bean>  

 

<bean id="b" class="B"  autowire="byType"></bean>

 

 

 

applicationContext.xml:

<bean id="a"  class="A"></bean>

<bean id="b"  class="B"></bean>

1、属性名字private IB b;的setB(Source source)的"B"必须和applicationContext.xml里面对应的bean id的名字相同

2、在申明里给所有bean配置一个属性.default-autowire="byName"(通过名字自动装配):  

<?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-2.0.xsd"
       default-autowire="byName">       有byName,byType,constructor和autodetect 4种装配方式

 byName的name是java中setXxxx 的Xxxx, 和上面设置的Source source中source拼写毫无关系

 byType 的Type是指setB(Source source)中参数的类型

 constructor在容器中寻找与需要自动装配的bean的构造函数参数一致的一个或多个bean

 autodetect:首先尝试使用constructor来自动装配,然后再使用byType方式

 

基于annotation注解方式的自动装配 

注解形式配置(注解方式的目的就是为了简化 XML 配置文件;JDK5、Spring2.5 版本之前版本不支持):

组件自动扫描功能:
 首先需要在 applicationContext.xml 中添加<context:component-scan/>

(使用此标签的前提是必须具有 xmlns:context 命名空间
<beans xmlns:context="http://www.springframework.org/schema/context">
   <context:component-scan base-package="king.demo5"></context:component-scan>
</beans>)
 1)  扫描 Bean 组件的注解,替代 xml 中的<bean>元素的定义
     @Service  用于 Service 业务组件
     @Control  用于 Action 控制组件
     @Respository  用于 DAO 数据访问组件
     @Component  用于其他组件
     Bean 组件扫描到容器后,默认名字为类名(首字母小写)如果需要自定义名称可以使用@Service("id 名")
 2)  依赖注入的注解标记
     @Resource  按名称@Resource(name="id 名") //JDK 提供的,先按类型,后按名称来自劢装配
     @AutoWired  按名称    //Spring 提供的,先按名称,后按类型来自劢装配
     @Autowired
     @Qualifier("id 名")
 3)  其他注解
     @Scope  等价于<bean scope="">
     @PostConstruct  等价于<bean init-method="">
     @PreDestroy  等价于<bean destroy-method="">