SSM框架之Spring

荒凉一梦 提交于 2020-10-28 09:16:29

IoC (Inversion of Control)

控制反转:对对象(beans)控制权的转移,从程序代码本身反转到了外部容器(xml配置文件, applicationContext.xml)

  • 对象的创建不是在view层,而是通过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">
      
   <!-- 注册Service 
                                               底层相当于ISomeService service = new SomeServiceImpl();
   -->
   <bean id="myService" class="service.SomeServiceImpl"/>
    
</beans>

程序与配置文件:

ApplicationContext容器:反应速度快/占用资源

ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");       //创建容器对象(对象bean也创建了)
ISomeService service = (ISomeService) ac.getBean("myService");                              //从容器获取对象   
service.doSome();

BeanFactory容器:反应速度慢/省资源(因为scope="prototype"的存在,已弃用)

BeanFactory bf = new XmlBeanFactory(new ClassPathResource("applicationContext.xml"));        //创建容器对象(对象bean没创建)
ISomeService service = (ISomeService) bf.getBean("myService");            
service.doSome();

bean的装配

装配即对象的生成

(1)默认方式

  • 调用类的无参构造器
<bean id="myService" class="ba01.SomeServiceImpl"/>

(2)动态工厂bean

  • 通过工厂类创建对象
<!-- 注册动态动态工厂 -->
<bean id="factory" class="ba02_dynamicF.ServiceFactory"/>
<!-- 注册Service :动态工厂Bean -->
<bean id="myService" factory-bean="factory" factory-method="getSomeService" scope="prototype"/>     //通过factory对象中的getSomeService方法创建myService对象   //scope:原型模式,每次对象都是新的(获取对象的是否才创建对象)

(3)静态工厂bean

<bean id="myService" class="ba03_silenceF.ServiceFactory" factory-method="getSomeService"/>    <!-- 相当于ServiceFactory.getSomeService -->静态工厂不需要创建对象

(4)bean后处理器

(5)bean的生命周期

基于XML的DI(依赖注入)

注入:对对象属性赋值

(1)分类

  • 设值注入:通过<property>,前提:在类里面有set方法
<bean id="myService" class="ba06.SomeServiceImpl"
      init-method="setUp" destroy-method="tearDown">
      
   <property name="adao" value="aaa"/>                      <!-- 给对象属性注入值 -->
   <property name="bdao" value="bbb"/>
  • 构造注入:

(2)集合属性注入值

<property name="myList" value="大兴,亦庄"/>

(3)指定多个配置文件

ApplicationContext ac = new ClassPathXmlApplicationContext("spring-*.xml");         //可变参数

基于注解的DI

注释:替换spring配置文件中bean的注册

@Component(value="mySchool")                 //表示当前类被Spring容器所管理
public class School {
   @Value(value="清华大学")
   private String name;

 

AOP (Aspect Orient Programming)

面向切片编程:切面——交叉业务逻辑(通知advice/顾问advisor,对主业务的增强),主业务逻辑(需要做的,在接口中定义的方法)

aop思想让系统业务逻辑和主业务逻辑分开开发,底层使用动态代理增强主业务逻辑

术语:

  1. 通知(Advice)
  2. 连接点(JoinPoint)
  3. 切入点(Pointcut)
  4. 切面(Aspect):包含通知的类,对目标方法增强的类
  5. 引入(introduction)
  6. 目标(target)
  7. 代理(proxy)
  8. 织入(weaving)

(1)Advice通知

  • 前置通知:目标方法执行之前执行
public class MyMethodBeforeAdvice implements MethodBeforeAdvice {
   //当前方法在目标方法执行前执行
   //method:目标方法
   //args:目标方法的参数列表
   //target:目标对象
   @Override
   public void before(Method method, Object[] args, Object target) throws Throwable {
      //对目标方法的增强代码写在这里!
      System.out.println("执行前置通知方法");
   }
}
<!-- 注册目标对象 -->
<bean id="someService" class="aop01.SomeServiceImpl"/>

 <!-- 注册切面:通知 -->
<bean id="myAdvice" class="aop01.MyMethodBeforeAdvice"/>
 
 <!-- 生成代理对象 -->
<bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
   <!-- 指定目标对象 -->
   <property name="target" ref="someService"/>                    <!-- 相当于传递给invoke的target:实现类对象 -->
   <!-- 指定切面 -->
   <property name="interceptorNames" value="myAdvice"/>
</bean>
public class MyTest {
   @Test
   public void test01() {                                      
      ApplicationContext ac = new ClassPathXmlApplicationContext("aop02/applicationContext.xml");   
      ISomeService service = (ISomeService) ac.getBean("serviceProxy");                                //代理对象
      service.doFirst();
      System.out.println("=================");
      service.doSecond();
   }
}
  • 后置通知:目标方法执行之后执行
public class MyAfterReturningAdvice implements AfterReturningAdvice {
   //在目标方法执行之后执行
   //returnValue:目标方法的返回值,可以获取但是不能改变
   @Override
   public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
      System.out.println("执行后置通知方法 returnValue=" + returnValue);
   }
}
<!-- 注册目标对象 -->
<bean id="someService" class="aop02.SomeServiceImpl"/>

 <!-- 注册切面:通知 -->
<bean id="myAdvice" class="aop02.MyAfterReturningAdvice"/>
 
 <!-- 生成代理对象 -->
<bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
   <property name="target" ref="someService"/>                    <!-- 相当于传递给invoke的target:实现类对象 -->
   <property name="interceptorNames" value="myAdvice"/>
</bean>
  • 环绕通知:目标方法执行前后都执行
public class MyMethodinterceptor implements MethodInterceptor {
   @Override
   public Object invoke(MethodInvocation invocation) throws Throwable {
      System.out.println("执行环绕通知:目标方法执行之前");
      //执行目标方法
      Object result = invocation.proceed();                      //类似于method.invoke()
      System.out.println("执行环绕通知:目标方法执行之后");
      return result;                                              //可获取目标方法结果,且能修改
   }
}
  • 异常通知:当目标方法抛出指定类型的异常时,执行当前方法
public class MyThrowsAdvice implements ThrowsAdvice {
   public void afterThrowing(UsernameException ex) {
      System.out.println("发生用户名异常:" + ex.getMessage());
   }
   public void afterThrowing(PasswordException ex) {
      System.out.println("发生密码异常:" + ex.getMessage());
   }
   //其他异常执行该方法
   public void afterThrowing(Exception ex) {
      System.out.println("异常:" + ex.getMessage());
   }
}

 

(2)Advisor顾问

通知会增强所有的目标方法,增强某些目标方法需要用顾问,对通知进行了包装

  • 名称匹配切入点顾问
<!-- 注册目标对象 -->
<bean id="someService" class="aop05_advisor.SomeServiceImpl"/>

 <!-- 注册切面:通知 -->
<bean id="myAdvice" class="aop05_advisor.MyAfterReturningAdvice"/>
 
 <!-- 注册切面:顾问 -->
<bean id="myAdvisor" class="org.springframework.aop.support.NameMatchMethodPointcutAdvisor">          //名称匹配
   <!-- 指定通知 -->
   <property name="advice" ref="myAdvice"/>
   <!-- 指定通知切入点 -->                                                    //*****
   <!-- <property name="mappedName" value="doFirst"/> -->
   <property name="mappedNames" value="doFirst,doThird"></property>
</bean>

 <!-- 生成代理对象 -->
<bean id="serviceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
   <property name="target" ref="someService"/>                    
   <property name="interceptorNames" value="myAdvisor"/>                    //*****代理用的顾问
</bean>
  • 正则表达式匹配切入点顾问
<!-- 注册目标对象 -->
<bean id="someService" class="aop06_advisor.SomeServiceImpl"/>

 <!-- 注册切面:通知 -->
<bean id="myAdvice" class="aop06_advisor.MyAfterReturningAdvice"/>
 
 <!-- 注册切面:顾问2 -->
<bean id="myAdvisor" class="org.springframework.aop.support.RegexpMethodPointcutAdvisor">
   <!-- 指定通知 -->
   <property name="advice" ref="myAdvice"/>
   <!-- 指定通知切入点 -->
   <property name="pattern" value=".*doFirst"/>                           <!-- 正则表达式(方法全路径)  .* —— 字符出现多次 -->
</bean>
  • 自动代理生成器DefaultAdvisorAutoProxyCreator

不用指定需要代理的对象,都会生成代理,引用的也直接是目标对象

  • 名称自动代理生成器BeanNameAutoProxyCreator

 

(3)AspectJ对AOP的实现

AspectJ:是一个面向切面的框架,定义了AOP语法。

Spring并入了AspectJ框架

AspectJ和Spring对AOP实现的区别:

  1. aspectj多一个最终通知(无论怎样都会执行)

切入点表达式:

 

AspectJ基于注解的AOP:

  • 前置通知
<!-- 注册切面 -->
<bean id="myAspect" class="com.bjpowernode.annotation.MyAspect"/>

<!-- 注册目标对象 -->
<bean id="someService" class="com.bjpowernode.annotation.SomeServiceImpl"/>

<!-- 注册AspectJ的自动代理 -->
<aop:aspectj-autoproxy/>
@Before("execution(* *..ISomeService.doFirst(..))")       //切入点表达式
public void myBefore() {
   System.out.println("执行前置通知方法");
}

 

 

AspectJ基于XML的AOP:

<!-- 注册切面 -->
<bean id="myAspect" class="com.bjpowernode.xml.MyAspect"/>

<!-- 注册目标对象 -->
<bean id="someService" class="com.bjpowernode.xml.SomeServiceImpl"/>

<!-- AOP配置 -->                                                                //*****
<aop:config>
   <aop:pointcut expression="execution(* *..ISomeService.doFirst(..))" id="doFirstPointcut"/>
   <aop:pointcut expression="execution(* *..ISomeService.doSecond(..))" id="doSecondPointcut"/>
   <aop:pointcut expression="execution(* *..ISomeService.doThird(..))" id="doThirdPointcut"/>
   
   <aop:aspect ref="myAspect">
      <aop:before method="myBefore" pointcut-ref="doFirstPointcut"/>
      <aop:before method="myBefore(org.aspectj.lang.JoinPoint)" pointcut-ref="doFirstPointcut"/>
      
      <aop:after-returning method="myAfterReturning" pointcut-ref="doSecondPointcut"/>
      <aop:after-returning method="myAfterReturning(java.lang.Object)" pointcut-ref="doSecondPointcut" returning="result"/>
      
      <aop:around method="myAround" pointcut-ref="doSecondPointcut"/>
      
      <aop:after-throwing method="myAfterThrowing" pointcut-ref="doThirdPointcut"/>
      <aop:after-throwing method="myAfterThrowing(java.lang.Exception)" pointcut-ref="doThirdPointcut" throwing="ex"/>
      
      <aop:after method="myAfter" pointcut-ref="doThirdPointcut"/>
   </aop:aspect>
</aop:config>
// 切面
public class MyAspect {
   
   public void myBefore() {
      System.out.println("执行前置通知方法");
   }
}

 

 

Spring与Dao

Spring与JDBC模板

为了避免直接使用JDBC带来复杂和冗长的代码,Spring提供了一个强有力的模板类jdbcTemplate来简化JDBC操作

(1)基础操作

  • 注册数据源
<bean id="myDataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
   <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
   <property name="url" value="jdbc:mysql://127.0.0.1:3366/test"/>
   <property name="username" value="root"/>
   <property name="password" value="111"/>
</bean>
  • 注册jdbcTemplate
<!-- 注册JdbcTemplate -->
<!-- 
<bean id="myJdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
   <property name="dataSource" ref="myDataSource"/>
</bean>
<bean id="studentDao" class="com.bjpowernode.dao.StudentDaoImpl">
   <property name="jdbcTemplate" ref="myJdbcTemplate"/>
</bean>
  • 注册Dao
<!-- 注册Dao -->
<bean id="studentDao" class="com.bjpowernode.dao.StudentDaoImpl">              //含具体增删改查
   <property name="dataSource" ref="myDataSource"/>
</bean>
  • 注册服务
<!-- 注册Service -->
<bean id="studentService" class="com.bjpowernode.service.StudentServiceImpl">
   <property name="dao" ref="studentDao"/>                                        //***依赖注入
</bean>

注:<property name="dao" ref="studentDao"/>   依赖注入,初始化对象属性,在studentService对象中可使用dao对象中的方法,dao对象中的方法含有sql语句,sql语句通过jdbc模板对象与数据库操作

(2)进阶

  • 查询返回结果得封装
public List<Student> selectAllStudents() {
   String sql = "select id,name,age from student";
   return this.getJdbcTemplate().query(sql, new StudentRowMapper());
}
public class StudentRowMapper implements RowMapper<Student> {

   // rs:当查询出总的结果集后,框架会自动遍历这个结果集,每一次遍历的一行数据,都会被存放到
   //     这个方法的rs参数中。也就是说,这里的rs代表的是一行数据,并非所有查询结果。换个角度
   //     来说,只要能执行到这个方法,就说明这里的rs不会是空的
   @Override
   public Student mapRow(ResultSet rs, int rowNum) throws SQLException {
      Student student = new Student();
      student.setId(rs.getInt("id"));
      student.setName(rs.getString("name"));
      student.setAge(rs.getInt("age"));
      return student;
   }

 

Spring与事务管理

事务:数据库概念即关于数据库的一系列操作

Spring事务默认回滚方式:发生运行异常时回滚,发生受查异常提交

事务管理主要是防止数据库未按要求更改而出错

>>>将事务管理作为切面,在目标方法执行后执行,如果整个目标方法执行没出错,则事务提交,否则事务回滚

事务管理的三种方法:

(1)事务代理工厂

<!-- ================================= AOP ==================================== -->

<!-- 注册事务管理器 -->
<bean id="myTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
   <property name="dataSource" ref="myDataSource"/>
</bean>

<!-- 生成事务代理对象 -->
<bean id="serviceProxy" class="org.springframework.transaction.interceptor.TransactionProxyFactoryBean">
   <property name="transactionManager" ref="myTransactionManager"/>
   <property name="target" ref="buyStockService"/>                             //切面
   <property name="transactionAttributes">
      <props>
         <prop key="open*">ISOLATION_DEFAULT,PROPAGATION_REQUIRED</prop>      //以open开始的方法
         <!-- 
            -异常:表示发生指定异常后回滚,这时的异常通常是受查异常
            +异常:表示发生指定异常后提交,这时的异常通常是运行时异常
          -->
         <prop key="buyStock">ISOLATION_DEFAULT,PROPAGATION_REQUIRED, -BuyStockException</prop>
      </props>
   </property>
</bean>

 

(2)事务注解

 

(3)使用Aspect的AOP配置

<!-- ================================= AOP ==================================== -->
   
   <!-- 注册事务管理器 -->
   <bean id="myTransactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
      <property name="dataSource" ref="myDataSource"/>
   </bean>
   
   <!-- 注册事务通知 -->
   <tx:advice id="txAdvice" transaction-manager="myTransactionManager">
      <tx:attributes>
         <!-- 这里指定的是:为每一个连接点指定所要应用的事务属性 -->
         <tx:method name="open*" isolation="DEFAULT" propagation="REQUIRED"/>
         <tx:method name="buyStock" isolation="DEFAULT" propagation="REQUIRED" rollback-for="BuyStockException"/>
      </tx:attributes>
   </tx:advice>
   
   <!-- AOP配置 -->
   <aop:config>
      <!-- 这里指定的是切入点 -->
      <aop:pointcut expression="execution(* *..service.*.*(..))" id="myPointcut"/>
      <aop:advisor advice-ref="txAdvice" pointcut-ref="myPointcut"/>
   </aop:config>
</beans>

 

Spring与MyBatis整合

(1)mapper动态代理

MyBatis:

  • 主配置文件中的不用配置据库连接池(Spring配置文件中)
<configuration>
   <typeAliases>
      <package name="com.bjpowernode.beans"/>   <!--别名,简单类名代替全路径名-->
   </typeAliases>
   <mappers>
      <package name="com.bjpowernode.dao"/>     <!--注册映射文件-->
   </mappers>
</configuration>
  • dao不是在程序中通过sqlsessionFactory生成,而是在Spring配置文件中注入
<context:property-placeholder location="classpath:jdbc.properties"/>

<bean id="mySqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
   <property name="configLocation" value="classpath:mybatis.xml"/>
   <property name="dataSource" ref="myDataSource"/>
</bean>

<!-- 生成Dao的代理对象 -->
<bean id="studentDao" class="org.mybatis.spring.mapper.MapperFactoryBean">
   <property name="sqlSessionFactory" ref="mySqlSessionFactory"/>
   <property name="mapperInterface" value="com.bjpowernode.dao.IStudentDao"/>
</bean>

<!-- 注册Service -->
<bean id="studentService" class="com.bjpowernode.service.StudentServiceImpl">
   <property name="dao" ref="studentDao"/>
</bean>

(2)支持扫描的mapper动态代理,为dao包底下的所有类生成代理对象

<!-- 生成Dao的代理对象
   当前配置会为指定的基本包中所有的接口生成代理对象
 -->
<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
   <property name="sqlSessionFactoryBeanName" value="mySqlSessionFactory"/>
   <property name="basePackage" value="com.bjpowernode.dao"/>
</bean>

 

 

Spring与Web整合

 

 

 

 

 

 

 

 

 

 

 

 

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!