Spring回顾一

Spring是一个开源的控制反转(Inversion of Control, IoC)和面向切面的(AOP, Aspect-Oriented Programming)的容器框架,它的主要目的是简化企业的开发。

所谓控制反转就是应用本身不负责依赖对象的创建及维护,依赖对象的创建及维护是由外部容器负责的,这样控制权就由应用转移到了外部容器,控制权的转移就是所谓反转

所谓依赖注入(Dependency Injection)就是指:在运行时,由外部容器动态地将依赖对象注入到组件中

Spring的好处:

减低组件之间的耦合度,实现软件各层之间的解耦

可以使用Spring提供的众多服务,如:事务管理器,消息服务等等。

容器提供单例模式的支持

容器提供了AOP技术

容器提供了众多的辅助类,使用这些类能够加快应用的开发

Spring对于主流的应用框架提供了集成的支持

对于spring容器,提供了很多的服务,但这些服务不是默认为应用打开的。如果提高服务较少则认为是轻量级的,否则则认为是重量级的。

spring用到的核心jar文件有两个:

dist/spring.jar

lib/jakarta-commons/commons-logging.jar

如果使用了切面编程(AOP),还需要下列的jar文件

lib/aspectj/aspectjweaver.jaraspectjrt.jar

lib/cglig/cglib-nodep-2.1-3.jar

如果使用了JSP-250中的注解,

@Resource/@PostConstruct/@PreDestory,还需要下列jar文件

lib/j2ee/common-annotations.jar.

 

实例化Spring容器常用的两种方式:

方法一:

类路径下寻找配置文件来实例化容器

ApplicationContext ctx =

new ClassPathXmlApplicationContext(new String[]{“bean.xml”});

方法二:

文件系统路径下寻找配置文件实例化容器

ApplicationContext ctx =

new FileSystemXmlApplicationContext(new String[]{“d:/beans.xml”});

编写spring配置文件时不出现帮助信息

由于springschema文件位于网络上,如果机器不能连接到网络上,那么在编写配置信息时候无法出现提示信息,解决办法有两种:

1.     让机器上网eclipse会自动从网络上下载schema文件并缓存到本地硬盘上

2.     手动添加schema文件,方法如下:

windows->preferences->myeclipse->files and editors ->xml->xmllocation ”add”,在出现的窗口中的Key Type中选择URL,location中选择”File System”,然后在spring解压目录的dist/resources目录中选择spring-beans-2.5.xsd,回到设置窗口的时候不要急着关闭窗口,应把窗口中的Key Type改为Schema location,Key

改为http://www.springframework.org/schema/beans/srping-beans

-2.5.xsd.

<beanid属性和name属性,name属性可以包含特殊字符例如:”/sd/

 

三种实例化bean的方式:

1.     使用类构造器实例化

<bean id=”orderService” class=”cn.itcast.OrderServiceBean”>

2.     使用静态工厂的方法实例化

<bean id=”personService” class=”cn.itcast.service.OrderFactory” factory-method=”createOrder” />

3.     使用实例化工厂的方法实例化

<bean id=”personServiceFactory” class=”cn.itcast.service.OrderFactory” />

<bean id=”personSercie” factory-bean=”personServiceFactory” factory-method=”createOrder”>

 

Bean的作用域:

.singleton在每个Spring IoC容器中一个bean定义只有一个对象实例,默认情况下会在容器启动时初始化bean.但我们可以指定Bean节点的lazy-init=”true”来延迟初始化bean,这时候,只有第一次获取bean会才初始化bean。如:

<bean id=”xxx” class=”cn.itcast.OrderServiceBean” lazy-init=”true” />

如果想对所有的bean都应用延迟初始化,可以在跟节点beans设置default-laza-init=”true”,如下: <beans default-lazy-init=”true”>

.prototype 每次从从其获取bean都是新的对象。

以下仅用于Web Bean

.request

.session.

.global session

 

Spring管理Bean的声明周期:

init-method: bean初始化实例时,调用初始化方法。

destroy-method bean被销毁时执行的方法

AbstractApplicationContext.close()方法用于关闭Spring容器

Spring的依赖注入:

使用内部bean,但该bean不能被其他bean使用:

<bean id=”orderService” class=”cn.itcast.service.OrderServiceBean”>

<property name=”orderDao”>

      <bean class=”cn.itcast.service.OrderDaoBean” />

</property>

</bean>

 

JavaBean是一种特殊的Java类,主要用于传递 数据信息,这种java类中的方法主要用于访问私有的字段,且方法名符合某种命名规则。

如果要在两个模块之间传递多个信息,可以将这些信息封装到一个JavaBean中,这种JavaBean的实例对象称之为值对象(Value Object,简称VO)。这些信息在类中用私有字段来存储,如果读取或设置这些字段的值,则需要通过一些相应的方法来访问。JavaBean的属性是根据启动的settergetter方法来确定的,而不是根据其中的成员变量。如果方法名为setId,中文意思即为设置id,至于你把它设置到那个变量上,则不用关心,如果方法名为getId,则属性名即为id.

JDK中提供了对JavaBean进行操作的一些API。这套API就称为内省

spring集合类型的封装:

<property name="sets">

           <set>

              <value>value1</value>

              <value>value2</value>

              <value>vaule3</value>

              <value>value4</value>

           </set>

       </property>

       <property name="lists">

           <list>

              <value>list1</value>

              <value>list2</value>

              <value>list3</value>

           </list>

       </property>

       <property name="maps">

           <map>

              <entry key="key1" value="value1" />

              <entry key="key2" value="value2" />

           </map>

       </property>

       <property name="props">

           <props>

              <prop key="p1">v1</prop>

           </props>

       </property>

 

spring依赖注入的实现:

private static class MyApplicationContect {

       public static Object getBean(String name) throws Exception {

          

           Map<String, String> nsMap = new HashMap<String, String>();

          

           // 加入命名空间

           nsMap.put("ns", "http://www.springframework.org/schema/beans");

          

           // 创建beans/bean的路径

           XPath xsub = document.createXPath("/ns:beans/ns:bean[@id='" + name + "']");

          

           // 设置命名空间

           xsub.setNamespaceURIs(nsMap);

          

           Element ele = (Element)xsub.selectSingleNode(document);;

           System.out.println(ele.attributeValue("class"));

          

           Object retValue = Class.forName(ele.attributeValue("class")).newInstance();

          

           for (Iterator<?> iter=ele.elementIterator("property"); iter.hasNext();) {

             

              Element property = (Element)iter.next();

              String propName = property.attributeValue("name");

             

              if (property.attributeValue("value") != null) {

                  String strValue = property.attributeValue("value");

                  Class<?> paraType = retValue.getClass().getDeclaredField(propName).getType();

                  Object value = ConvertUtils.convert(strValue, paraType);

                 

                  setProperty(retValue, propName, value);

                  //BeanUtils.setProperty(retValue, propName, strValue);

              } else {

                  String ref = property.attributeValue("ref");

                  Object obj2 = getBean(ref);

                 

                  setProperty(retValue, propName, obj2);

                  //BeanUtils.setProperty(retValue, propName, obj2);

              }

           }

           return retValue;

       }

      

       private static void setProperty(Object object, String propertyName,

              Object propertyValue) throws IntrospectionException,

              IllegalAccessException, InvocationTargetException {

           PropertyDescriptor propertyX = new PropertyDescriptor(propertyName, object.getClass());

           Method methodSetX = propertyX.getWriteMethod();

           methodSetX.setAccessible(true);

           methodSetX.invoke(object, propertyValue);

       }

    }

 

依赖注入共有三种:

使用构造器注入

使用属性setter方法注入

使用Field注入(用于注解注入)

注入依赖对象可以采用手工装配或自动装配,在实际应用中建议使用手工装配,因为自动装配会产生未知情况,开发人员无法预见最终的装配结果。

手工装配依赖对象,在这种方式中又有两种编程方式。

1.     xml配置中,通过在bean节点下配置(通过构造器注入,通过setter方法注入)

2.     java代码中使用@Autowired@Resource注解方式进行装配。但我们需要在xml配置文件中配置下面的

<context:annotation-config />这个配置方式注册了多个注释进行解析处理的处理器

AutowireAnnotationBeanPostProcessor

CommonAnnotationBeanPostProcessor,PersistenceAnnotationBeanPostProcessorRequiredAnnotationBeanPostProcessor

注:@Resource注解在spring安装目录的lib/j2ee/common-annotations.jar

java代码中使用@Autowired@Resource注解方式进行装配,这两个注解的区别是:@Autowired默认按类型装配@Resource默认按名称装配,当找不到与名称匹配的bean时,才会按类型装配

@Autowired

private PersonDao personDao; // 用于字段上

@Autowired

public void setOrderDao(OrderDao orderDao) { // 用于属性的setter方法上

}

@Autowired注解是按类型装配依赖对象,默认情况下它要求依赖对象必须存在,如果允许null,可以设置它的required属性为false,如果我们想使用按名称装配,可以结合@Qualified注解一起使用。如下:

Autowired @Qualifer(“personDaoBean”);

  private PersonDao personDao;

@Resrouce注解和@Autowired一样,也可以标注在字段或属性的setter方法,但它默认按名称装配,名称可以通过@Resourcename属性指定,如果没有指定name属性,当注解标注在字段上,即默认取字段的名称作为bean名称寻找依赖对象,当注解标注在属性的setter方法上,即默认取属性名作为bean名称寻找依赖对象。

@Resource(name=”personDaoBean”)

private PersonDao personDao // 用于字段上

注意:如果没有指定name属性,并且按照默认的名称仍然找不到依赖对象时,@Resource注解会回退到按类型装配,但一旦指定了name属性,就只能按名称装配了。

 

自动装配的实现:<bean id=”” class=”” autowire=”byType”>

autowire属性取值如下:

.byType: 按类型装配,可以根据属性的类型,在容器中寻找跟类型匹配的bean,如果发现多个,那么就会抛出异常,如果没有找到,即属性值为null

.byName 按名称装配,可以根据属性的名称,在容器中寻找跟属性名相同的bean.如果没有找到,即属性值为null.

.constructorbyType的方式类似,不同之处在于它应用于构造器参数,如果在容器中没有找到与构造器参数类型一致的bean,那么将会抛出异常。

autodeleted,通过bean类的自省机制(introspection来决定是使用constructor还是byType方式进行自动装配。如果发现默认的构造器,那么将使用byType方式。

spring2.5为我们引入了组件自动扫描机制,他可以在类路径下寻找标注了@Component,@Service,@Controller,@Repository注解的类,并把这些类纳入进spring容器中管理,它的作用和在xml文件中使用bean节点配置组件是一样的,要使用自动扫描机制,我们需要在配置文件中配置以下信息:

<context:component-scan base-package=”cn.itcast”>

其中base-package为需要扫描的包(含子包)

@Service用于标注业务层组件@Controller用于标注控制层组(struts中的action)@Repository用于标注数据访问组件,即DAO组件,而@Component泛指组件,当组件不好归类时,我们可以使用这个注解进行注册。

 

Logo

开放原子开发者工作坊旨在鼓励更多人参与开源活动,与志同道合的开发者们相互交流开发经验、分享开发心得、获取前沿技术趋势。工作坊有多种形式的开发者活动,如meetup、训练营等,主打技术交流,干货满满,真诚地邀请各位开发者共同参与!

更多推荐