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思想让系统业务逻辑和主业务逻辑分开开发,底层使用动态代理增强主业务逻辑
术语:
- 通知(Advice)
- 连接点(JoinPoint)
- 切入点(Pointcut)
- 切面(Aspect):包含通知的类,对目标方法增强的类
- 引入(introduction)
- 目标(target)
- 代理(proxy)
- 织入(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实现的区别:
- 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整合
来源:oschina
链接:https://my.oschina.net/u/4098328/blog/3089316