博客信息

Spring综述

0
发布时间:『 2016-09-24 18:22』  博客类别:java框架  阅读(472) 评论()

一、概述

     a>、核心技术 : IOC与AOP

b>、开发为什么需要面向接口而不是实现

   接口降低一个组件与整个系统的藕合程度,当该组件不满足系统需求时,可以很容易的将该组件从系统中替换掉,而不会对整个系统产生大的影响

c>、面向接口编口编程的难点在于如何对接口进行初始化,(使用工厂设计模式)

二、搭建开发环境

     a>、下载开发包,在工程中添加jar包

  aa>、IOC : spring-core.jar,spring-context.jar,spring-beans.jar,spring-expression.jar,spring-test.jar,commons-logging.jar

  bb>、AOP : spring-aop.jar,spring-aspects.jar,cglib.jar,aopalliance.jar,aspectjrt.jar,aspectjweaver.jar

  cc>、整合hibernate : spring-jdbc.jar,spring-tx.jar,string-orm.jar

b>、准备一个spring的配置文件

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

</beans>

c>、从容器中获取bean的方法

        UserBean user1 = (UserBean)context.getBean("user1");

        UserBean user2 = contextBean(UserBean.class);

        UserBean user3 = contextBean("user2",UserBean.class); //容器中有多个UserBean类型对象时使用

    


三、为什么要用Spring

     a>、解藕,项目中各层代码之间不需要再写连接性的代码,能轻松完成面向接口开发

b>、Spring框架提供了AOP的功能,可以方便的为系统中的组件添加服务逻辑

c>、Spring框架提供了声明式的事务管理功能,在项目开发中不需要考虑复杂的事务控制问题

d>、Sprng框架对其它注流框架如Hibernate,Struts等提供了很好的支持,可以降低项目中使用这些框架的难度,且更容易被替换

四、关于IOC

     a>、spring框架只服务于IOC容器中的对象,如果对象不在IOC容器中,不管在对象做了什么与spring有关的设定,都与spring

b>、ioc : Inversion of Control 控制反转

c> ID : dependence Injection 依赖注入

五、<bean>的主要属性

      id : 获取Bean的ID号,spring的早期版中,该属性的值不能有特殊字符

 name : 与ID一样标识对象的,其值可以包含特殊字符

 class : 

 scope : (singleton:单例,只创建该类的一个对象/prototype : 每次从容器中取对象时都创建该类的一个新的实例) bean的作用域

      lazy-init : 延迟初始化,指的是ApplicationContext启动时是否创建该对象

 init-method :  生命周期回调方法 

 destroy-method : 

 

 


六、BeanFactory与ApplicationContext的差别:

     a>、在实际应用中,用户有时候不知道到底是选择BeanFactory接口 还是ApplicationContext接口。 BeanFactory接口擅长于处理bean的初始化和配置,而 ApplicationContext接口除了处理上述工作外,它还针对企业引用 提供了许多基础支持,比如事务处理和AOP。

        简而言之,一般把ApplicationContext接 口作为首选。

b>、创建对象的时机:BeanFactory在第一次取对象时才创建bean对象,而ApplicationContext在容器启动时就创建所有singleton作用域的对象

七、集合属性注入 : 如何向一个对象的集合属性(数组,Set,List,Map,Properties)上直接注入值

    

八、依赖注入的方式

     a>、set方法注入:调用属性的set方法

    <bean id="addr" class="com.sxt.spring.bean.Address">

             <property name="province" value="陕西省"/>

</bean>

b>、构造方法注入: 调用类的指定构造方法,在创建对象时注入依赖资源

   <bean name="user2"  class="com.sxt.spring.bean.UserBean" >

  <constructor-arg value="李四"/>

  <constructor-arg value="女"/>

  <constructor-arg value="25"/>

  <constructor-arg>

  <bean class="java.util.Date"></bean>

  </constructor-arg>

  <constructor-arg ref="addr"/>

       </bean>

c>、p名称空间注入: set注入的简写形式

        a>、打开p注入:在<beans>的开始标记中添加p名称空间:

<beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:p="http://www.springframework.org/schema/p"

xsi:schemaLocation="http://www.springframework.org/schema/beans

http://www.springframework.org/schema/beans/spring-beans.xsd">

        <bean name="user3"  

          class="com.sxt.spring.bean.UserBean"

          p:name = "王麻子"

          p:sex = "男"

          p:age = "30"

          p:address-ref="addr"

           >

          <property name="birth"><bean class="java.util.Date"/></property>

      </bean>

d>、field注入(仅针对引用类型),使用@Resource,@Autowired注解进行注入

   a>、打开注解注入:声明context名称空间,添加<context:annotation-config/>

 <beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:p="http://www.springframework.org/schema/p"

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-4.0.xsd">

   b>、在需要注入的属性或属性的set方法上,使用@Autowired或@Resource注解

   public class LoginAction {

@Autowired

private IUserService userService ;

}

c>、@Resource  : 默认按名称装配,如果按名称装配失败,会回退到按类型装配,在使用该注解时,可使用name属性,指定bean的ID,使用该属性后只能按名称装配

   @Autowired : 按类型装配,默认情况下要求所依赖的对象必须存在,也可以使用@Autowired(request=false),所依赖的资源可以不存在

            该注解可以配置@Qualifier("uuDao")一起使用,实现按名称装配

e>、自动装配(仅针对引用类型)

  <bean name="user4" class="com.sxt.spring.bean.UserBean" autowire="byName/byType/constructor"></bean>

九、自动扫描

      a>、打开自动扫描

   <context:component-scan base-package="com.sxt.spring"/>

b>、在需要被扫描的类上使用以下注解:

    @Controller  : 标注控制器

@Service     : 标注业务组件

@@Repository : 标注数据访问层

@Component   :泛指组件,当组件不好归类时使用

c>、默认情况下,对象在容器中的id为简单类名,首字毋小写,我们可以在使用注解时指定id,方法为:@Service("userService")



十、在测试用例中直接注入依赖对象

    @RunWith(SpringJUnit4ClassRunner.class)

@ContextConfiguration("/injection.xml")

public class LoginActionTest {

@Autowired

private LoginAction loginAction;


@Test

public void testLogin() {

loginAction.execute();

}

}

十一、AOP:面向切面编程

      a>、Filter,Struts2的Interceptor就是AOP编程

b>、AOP的技术需要用到代理(Proxy)设计模式

    原对象(Target)  -->   代理对象(Proxy)

aa>、代理对象具有被代理对象的所有功能

bb>、代理对象不能脱离被代理对象而独立存在的,业务逻辑代码由被代理对象完成

    cc>、对接口的代理:代理类与被代理类实现了同一接口,在开发时只能使用接口操作

         dd>、对类的代理:代理类是被代理类的子类

         ee>、AOP框架必须支持动态代理(提前不知道要代理谁,可以动态生成一个类的代理类)

     aaa>、JDK的API只支持接口的动态代理,即可以动态生成接口的实现类(类名格式为:$Proxy10),

 要对类进行动态代理,必须使用第三方库动态生成类的子类的字节码,如CGLib库(类名格式为:DeptServiceBean$$EnhancerBySpringCGLIB$$e5477967),javassist库

 

 

 

 c>、AOP的术语

        aa>、JoinPoint : 连接点

        bb>、Advice  : 通知

        cc>、PointCut : 切点

        dd>、Aspect = JoinPoint + Advice +  PointCut

        ee>、Advisor = Advice(含JoinPoint) + PointCut;

 

十二、在Spring框架中实施AOP

        a>、添加aop相关的jar

        b>、在spring配置文件中打开AOP的支持

            <bean class="org.springframework.aop.aspectj.annotation.AnnotationAwareAspectJAutoProxyCreator" >

              <property name="proxyTargetClass" value="true"/> 

            </bean>

        c>、开发切面Aspect

            @Aspect

public class TimerAspect {   

@Around("test()")

public Object advice(ProceedingJoinPoint pjp)throws Throwable {

long start = System.currentTimeMillis();

System.out.println( "方法" + pjp.getSignature().getName() + "开始于:" + String.format("%tF %<tT", start));  

Object obj = pjp.proceed();  //执行被代理对象的方法

long end = System.currentTimeMillis();

System.out.println("方法" + pjp.getSignature().getName() + "结束于:" + String.format("%tF %<tT", end)+ ",共执行" + (end - start) + "毫秒\n");

return obj;

}

@Pointcut("execution(* *(..))")

public void test() {}

}

        d>、在spring的配置文件中声明切面类

            <bean class="com.sxt.spring.aspect.TimerAspect"></bean>


        e>、连接点的类型

            @Before : 前置通知

            @AfterReturning : 后置通知

            @After : 最终通知

               try {


               }finally {

                  //..........

                }

            @AfterThrowing : 异常处理

              try {

              }catch(Throwable e) {

                   //.............

  throw e;

               }  

            @Around : 环绕通知


十三、切点函数execution()的使用

      @Before("execution(* *(..))")  : execution()是一个切点函数,* * (..)是该函数的参数,其格式为:

   <访问权限>? 返回值类型  包名+类名+方法名(参数类型) <throws 异常类型声明>

十四、基于Schema的方式进行AOP编程

      a>、添加AOP名称空间

   <beans xmlns="http://www.springframework.org/schema/beans"

xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

xmlns:p="http://www.springframework.org/schema/p"

xmlns:context="http://www.springframework.org/schema/context"

xmlns:aop="http://www.springframework.org/schema/aop"

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-4.0.xsd

http://www.springframework.org/schema/aop 

http://www.springframework.org/schema/aop/spring-aop-4.0.xsd">

       b>、开发切面类:不需要任何注解

      public class AfterAspect {

public void aaa() {

System.out.println("--------------------------");

System.out.println("    请关注:www.xasxt.com");

System.out.println("--------------------------\n");

}

}

c>、在配置文件中将类转换为Aspect

   <aop:config>

 <aop:pointcut expression="execution(public void *())" id="pp"/>

 <aop:aspect ref="afterAspect">

 <aop:after method="aaa" pointcut-ref="pp"/>

  </aop:aspect>

  </aop:config>


十五、全用PropertyPlaceholderConfigurer将配置值写入properties文件

       a>、在spring的配置文件中注册PropertyPlaceholderConfigurer类,指定其所使用的properties

      <bean class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">

 <property name="location" value="/jdbc.properties"/>

 </bean>

 或使用context名称空间下的元素

 <context:property-placeholder location="jdbc.properties"/>

  b>、在其它bean的定义中就可以直接使用properties文件中的key来引用其value

        <bean id="jdbcConfig" class="com.sxt.spring.test.JdbcConfig">

<property name="driverClassName"  value="${jdbc.driver}"/>

<property name="url"  value="${jdbc.url}"/>

<property name="username"  value="${jdbc.username}"/>

<property name="password"  value="${jdbc.password}"/>

 </bean>

 

十六、使用FactoryBean创建对象

       <!-- 如果一个类实现了FactoryBean接口,那么id标识的不再是该类的对象,而是它的getObject方法返回的对象 -->

       <bean id="jdbcConfig2" class="com.sxt.spring.test.JdbcConfigFactoryBean"/>

  

  

十七、Spring整合Hibernate 

      1>、添加所有框架的jar文件

 2>、准备Spring的配置文件,官方建议以applicationContext.xml

 3>、由Spring创建数据源(DBCP:添加dbcp的jar包)

 4>、由Spring创建SessionFactory

     

 5>、开发Dao

 

十八、数据访问层的开发及异常处理

      jdbc :   saveEmp()throws SQLExeption;

      hibernate :  saveEmp() throws HibernateException;

      JPA     :   saveEmp() throws PersistenceException;

      不管数据访问层使用什么样的技术,抛出的异常类型必须固定,否则的话数据访问层的变化可能就会影响业务逻辑层

 解决方案 : 自定义DaoExeption: saveEmp() throws DaoException

    saveEmp()throws DaoExcepton {

   try {

    session.save(emp);

}catch(HibernateException e) {

   throw new DaoException(e);

}

}

 

 

      业务层处理异常:

       try {

           saveEmp()

       } catch(?) {


       }   

       Spring的解决方案

  public class HibernateTemplate  {

      private SessionFactory sf;

      

  public void save(Object obj)throws DataAccessException {

   try {

       sf.getCurrentSession().save(emp);

   }catch(HibernateException e) {

      throw new DataAccessException(e);

   }

}   

  }

  

    1>、

 public class EmpDao {

     private HibernateTemplate ht;

     public void save(Employee emp) throws DataAccessException {

      ht.save(emp);

 }   

  }

2>、

public class EmpDao extends HibernateDaoSupport {

      public void save(Employee emp) throws DataAccessException {

       this.getHibernateTemplate().save(emp);

  }

}

3>、使用Hibernate原生API

public class EmpDao {

  private SessionFactory sf;

  public void save(Employee emp) {

     sf.getCurrentSession().save(emp);

  }

}

优点:这种DAO访问方式的主要优势在于它仅仅依赖于Hibernate API本身而无需引入任何Spring的类。 从无入侵性的角度来看,这一点非常吸引人。对于Hibernate开发人员来说也无疑更加自然

    缺点:这样的DAO访问方式会抛出原生 HibernateException (这是一个无需声明或捕获的unchecked exception), 这意味着,DAO的调用者只能以致命的错误来处理这些异常,除非完全依赖Hibernate自身的异常体系。 

   因而,除非你将DAO的调用者绑定到具体的实现策略上去,否则你将无法捕获特定的异常原因,诸如乐观锁异常。 这种折中平衡或许可以被接受,如果你的应用完全基于Hibernate或者无需进行特殊的异常处理

十九:声明式事务处理


    a>、对于Hibernate,事务处理这样做

      Session session = sf.getCurrentSession();

      Transaction tx = session.beginTransaction();

 try {

         session.save(obj);

 

         tx.commit();

        }catch(HibernateException e) {

           tx.rollback();

  throw e;

        }


b>、事务要加在业务方法上,而不是数据访问方法上


     public void 转账(Integer userId1,Integer userId2,double money) {  //业务方法

    -- 开始事务

//session.beginTransaction();

         User user1 = userDao.findById(userId1);

if(user1.getBalance() < money) {

   throw ServiceException("余额不足");

}

user1.setBalance(user1.getBalance() - money);

userDao.update(user1);

 

User user2 = userDao.findById(userId2);

user2.setBalance(user2.getBalance() + money);

userDao.update(user2);

 

logDao.log(userId1 + "向" + userId2 + "转账" + money);//写日志

--结束事务

// tx.commit();

     }


    c>、

<!-- 1、创建事务管理器对象 -->

<bean id="transactionManager" 

 class="org.springframework.orm.hibernate4.HibernateTransactionManager"

p:sessionFactory-ref="sessionFactory"/>

<!-- 2、声明事务属性Advice -->

<tx:advice id="txAdvice"  transaction-manager="transactionManager">

<tx:attributes>

<tx:method name="save*" isolation="DEFAULT" propagation="REQUIRED" read-only="false" timeout="-1" />

<tx:method name="update*"/>

<tx:method name="delete*" />

<tx:method name="*" read-only="true"/>

</tx:attributes>

</tx:advice>

<!-- 3、使用aop,将事务管理的代码加到业务对象的方法上 -->

<aop:config proxy-target-class="true">

  <aop:advisor advice-ref="txAdvice" pointcut="execution(* com.sxt.ems.service.*Service.*(..))"/>

</aop:config>


关键字:   Spring     框架  

上一篇:foreach循环原理

下一篇:Struts2综述

Copyright © 2012-2017 yinbin.lan 版权所有   京ICP备16047123号