spring学习笔记

一、概述
    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
  6>、为业务对象的方法使用声明式的事务管理
 
十八、数据访问层的开发及异常处理
      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整合Struts2
      a>、为什么要整合? 因为Action需要的业务对象在Spring的ioc容器中
  b>、如何整合(Action如何拿到业务对象),最理想的方式就是由spring的依赖注入机制自动注入
  c>、要使用自动注入,Action必须由Spring创建和管理
  d>、整合的要点就在于如何让struts2框架使用Spring容器中的Action,而不是自己创建Action
  e>、整合步骤
      aa>、在应用程序启动时启动spring容器,在web.xml中配置spring框架提供的一个监听器ContextLoaderListener,在spring-web.jar中
       <!-- 指定spring的配置文件,供ContextLoaderListener使用 -->
   <context-param>
  <param-name>contextConfigLocation</param-name>
  <param-value>classpath:applicationContext.xml</param-value>
</context-param>

   <!-- 在应用启动时启动spring -->
   <listener>
<listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>
</listener>
      bb>、让struts2使用spring的action:由struts2完成,添加struts2-spring-plugin.jar
     在spring框架中创建Action,注意scope属性
  <bean id="employeeAction" class="com.sxt.ems.web.action.EmployeeAction" scope="prototype">
<property name="empService" ref="empService"/>
<property name="deptService" ref="deptService"/>
</bean>

     在struts.xml中添加以下常量<constant name="struts.objectFactory" value="spring" />
action的配置中class属性的值不再写Action的类名,而是Action对象在spring中id
    
二一、如何在Filter或Servlet中访问Spring容器中的对象
WebApplicationContext context = WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
EmployeeService empService = context.getBean(EmployeeService.class);

二二、OpenSessionInViewFilter的使用
a>、在正常情况下,业务方法运行结束后,session就关闭了,通过业务方法所得到的对象如果其关联的属性没有被加载,这些属性就不能在jsp页面中被访问
b>、在业务方法中就要将之后可能用到的属性进行初始化:Hibernate.initialize(dept.getEmps());
c>、使用OpenSessionInViewFilter : 通过一个Filter拉长了session的作用域,它会在请求到达Servlet/Action之前打开session,在响应生成之后关闭session
   <filter>
   <filter-name>openSessionInView</filter-name>
   <filter-class>org.springframework.orm.hibernate4.support.OpenSessionInViewFilter</filter-class>
   </filter>
   <filter-mapping>
  <filter-name>openSessionInView</filter-name>
  <url-pattern>/*</url-pattern>
  </filter-mapping>

你可能感兴趣的:(spring)