Spring框架学习笔记

#Spring框架学习笔记#

一. 环境搭建

* 1.导入Spring的必须jar包

在这里插入图片描述

1.其中logging为日志包,其他为_必需包_

* 2.编写配置文件,命名为applicationContext.xml(Spring框架最大的容器同名)

编写原则如图:

icon

在beans标签后添加约束文件名

二. IoC Inversion of Context(Spring框架的控制反转,创建对象过程与开发者解耦)

  • 创建对象的方法

1.有参构造创建对象方法:

配置文件代码:

icon

测试类代码:

在这里插入图片描述

2.静态工厂创建对象方法:

配置文件代码:

icon

测试类代码:

icon

2.实例工厂创建对象方法:

配置文件代码:

!icon

测试类代码:

icon

* 给对象赋值的方法:

1.有参赋值方法,见有参构造创建对象方法(需要在pojo类里提供有参构造器);

2.子标签赋值方法(注入)

<!-- 子标签赋值方法 -->
<bean id="peo3" class="com.test01.pojo.People">
	<property name="name">
		<value>accer</value>
	</property>
	<property name="age">
		<value>10</value>
	</property>
	<property name="family">
		<list>
			<value>jack</value>
			<value>jade</value>
			<value>jazz</value>
		</list>
	</property>
	<property name="workplaces">
		<map>
			<entry key="1" value="beijing"></entry>
			<entry key="2" value="shanghai"></entry>
			<entry key="3" value="shenzhen"></entry>
		</map>
	</property>

3.依赖注入(DI:dependent injection):把另一个对象实例化,并注入当前对象的过程

    通过声明另一个当前类所持有的类的bean对象(并声明其中的参数),在当前bean标签内通过子标签调用

	<property name="work" ref="work"></property>
</bean>

<bean id="work" class="com.test01.pojo.work">
	<property name="workID" value="1001"></property>
	<property name="salary" value="6000"></property>
</bean>

三.Spring框架整合myBatis框架

  • 1.导入相关jar包

导入 mybatis 所有 jar和 spring 基本包,spring-jdbc,spring-tx,spring-aop,spring-web,spring 整合 mybatis 的包等;

  • 2.在WebContent文件夹下编写配置文件web.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">
      	
      	<!-- Spring数据源封装,用于获取数据库连接 -->
      	<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
      		<property name="driverClassName" value="com.mysql.jdbc.Driver"></property>
      		<property name="url" value="jdbc:mysql://localhost/stuinfo"></property>
      		<property name="username" value="root"></property>
      		<property name="password" value="root"></property>
      	</bean>
      	
      	<!--Spring对SqlSessionFactoy封装,用于获取myBatis的SqlSessionFactory对象 -->
      	<!-- ref属性表示将数据库连接对象注入对象factory -->
      	<bean id="factory" class="org.mybatis.spring.SqlSessionFactoryBean">
      		<property name="dataSource" ref="dataSource"></property>
      	</bean>
      	
      	<!-- Spring的扫描器,用于扫描指定包下的myBatis接口绑定文件(不能用于扫描mapper.xml!) -->
      	<!-- id可省略 -->
      	<bean class="org.mybatis.spring.mapper.MapperScannerConfigurer">
      		<property name="basePackage" value="com.test.mapper"></property>
      		<!-- 注入对象factory -->
      		<property name="sqlSessionFactory" ref="factory"></property>
      	</bean>
      	
      	<!-- Spring对Service的管理类 -->
      	<bean id="StudentService" class="com.test.services.impl.StudentServiceImpl">
      		<!-- 注入对象studentMapper-->
      		<property name="studentMapper" ref="studentMapper"></property>
      	</bean>
      	
      </beans>
    
  • 3.编写pojo类与service类

    pojo类正常编写,service类简写即可,必须要有get,set方法以便于设值注入(Spring已经进行封装,无需详细编写)

      public class StudentServiceImpl implements StudentService {
      	private StudentMapper studentMapper;
      	public StudentMapper getStudentMapper() {
      		return studentMapper;
      	}
      	public void setStudentMapper(StudentMapper studentMapper) {
      		this.studentMapper = studentMapper;
      	}
      	@Override
      	public List<student> showAll() throws IOException {
      		return studentMapper.selAll();
      	}
      }
    
  • 4.编写sevlet

    由于Spring框架未对servlet进行封装,因此编写servlet代码相对复杂

      public class StundetSevlet extends HttpServlet {
      	private static final long serialVersionUID = 1L;
      	private StudentService ss;
      	@Override
      	public void init() throws ServletException {
      		ApplicationContext ac =WebApplicationContextUtils.getRequiredWebApplicationContext(getServletContext());
      		ss=ac.getBean("StudentService",StudentServiceImpl.class);
      	}
      	protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      		request.setAttribute("student", ss.showAll());
      		request.getRequestDispatcher("index.jsp").forward(request, response);
      	}
      	protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
      		doGet(request, response);
      	}
      }
    

注释:init()方法中的代码代表在当servlet初始化时,即启动tomcat时即加载项目applicationContext,读取其中的配置文件,并对其内容(service)进行初始化,这一步对于运行servlet(业务)是必需的而且是预先完成的,由于Spring框架未实现此功能,因此采用了init方法来实现

四.AoP(Aspect oreinted Programming)面向切面编程

  • 1.基本概念

    1.在程序原有纵向执行流程中,针对某一个或某一些方法添加通知,形成横切面过程就叫做面向切面编程。(对源程序的扩展,且不影响源程序的运行)

    2.常用术语:

      2.1 原有功能: 切点, pointcut
    
      2.2 前置通知: 在切点之前执行的功能. before advice
    
      2.3 后置通知: 在切点之后执行的功能,after advice
    
      2.4 如果切点执行过程中出现异常,会触发异常通知.throws advice
    
      2.5 所有功能总称叫做切面. 5.6 织入: 把切面嵌入到原有功能的过程叫做织入
    
  • 2.Spring实现AoP方法:

    1.采取Schema-based方法:

    (1)导入相关jar包:

    注意:多导入的aopalliance和aspectjweaver为SpringAoP的支持包,此外,图中遗漏了commonsLogging包!

    icon

    (2)编写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"
      	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
      	
      	<!--引入AoP命名空间dtd文件-->
      	http://www.springframework.org/schema/aop
      	http://www.springframework.org/schema/aop/spring-aop.xsd">
      	
      	<!-- 配置:前置通知与后置通知对象 -->
      	<bean id="afterAdvice" class="com.testAOP.SchemaBased.AfterAdviceClass"></bean>
      	<bean id="beforeAdvice" class="com.testAOP.SchemaBased.BeforeAdviceClass"></bean>
      	
      	<!-- 配置切面 -->
      	<aop:config>
      		<!-- 配置切点所在的方法 *代表通配符,可在后面的包名后进行切点的配置(如通配同一包下,同一方法名等) -->
      		<aop:pointcut expression="execution(* com.testAOP.SchemaBased.demo.cutPoint2())"  id="pointCut" />
      		<!-- 配置前置通知方法与后置通知方法 -->
      		<aop:advisor advice-ref="beforeAdvice" pointcut-ref="pointCut"/>
      		<aop:advisor advice-ref="afterAdvice" pointcut-ref="pointCut"/>
      	</aop:config>
      	
      	<!-- 配置测试类 -->
      	<bean id="testSchemaBased" class="com.testAOP.SchemaBased.demo"></bean>
      </beans>
    

    (3)编写通知类:

      //前置通知类
      public class BeforeAdviceClass implements MethodBeforeAdvice {
      	//arg0代表切点方法对象(qualified name);arg1 代表切点传入的参数,arg2代表切点所属于的对象
      	@Override
      	public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
      		System.out.println("执行前置通知的方法");
      	}
      }
    
      //后置通知类
      public class AfterAdviceClass implements AfterReturningAdvice{
      	//arg0代表切点的返回值;arg1代表切点方法对象(qualified name);arg2 代表切点传入的参数,arg3代表切点所属于的对象
      	@Override
      	public void afterReturning(Object arg0, Method arg1, Object[] arg2, Object arg3) throws Throwable {
      		System.out.println("执行后置通知的方法");
      	}
      }
    

    (4)测试结果
    在这里插入图片描述

  • 2.采取Aspect-J方式配置切面抛出异常类:

(1)xml配置文件代码

<!-- 配置:某个切面的抛出异常类对象-->
<bean id="throwAdvice" class="com.testAOP.SchemaBased.ThrowAdvice" ></bean>

<!-- 配置切面 -->
<aop:config>
	<!-- 配置切点所在的方法 -->
	<aop:pointcut expression="execution(* com.testAOP.SchemaBased.demo.cutPoint2())"  id="pointCut" />
	<!-- 配置前置通知方法与后置通知对象 -->
	<aop:advisor advice-ref="beforeAdvice" pointcut-ref="pointCut"/>
	<aop:advisor advice-ref="afterAdvice" pointcut-ref="pointCut"/>
	<!-- 配置切面中抛出异常的方法位于的类对象 -->
	<aop:aspect ref="throwAdvice">
		<!-- after-throwing 代表通知类型,method代表方法名,pointcut-ref为方法所配置的切点对象,throwing代表所抛出的异常对象,必须添加,否则不显示异常结果 -->
		<aop:after-throwing method="ThrowException" pointcut-ref="pointCut" throwing="e"/>
	</aop:aspect>
</aop:config>

<!-- 配置测试类 -->
<bean id="testSchemaBased" class="com.testAOP.SchemaBased.demo"></bean>

(1)切面的抛出异常类的编写:

//传入的参数为程序执行异常时的异常对象e,名称必须与xml配置文件中的抛出异常类的声明一致
public class ThrowAdvice {
	public void ThrowException(Exception e){
		System.out.println("执行在切面中抛出异常的方法:"+e.getMessage());
	}
}
  • 3.采取schema-based方法配置环绕通知类(整合前置通知与后置通知)

(1)环绕通知类的编写

public class SurroundAdvice implements MethodInterceptor{
	@Override
	public Object invoke(MethodInvocation arg0) throws Throwable {
		System.out.println("执行环绕通知的前置通知方法");
		Object proceed = arg0.proceed();
		System.out.println("执行环绕通知的后置通知方法");
		return proceed;
	}
}

(2)xml配置文件的编写(与前置后置通知类编写原则一致)

  • 4.采取Aspect-J方式配置切面

(1)编写通知类

(2)配置xml配置文件,对文件类,测试类的配置略;

【1】若切点含参,则在配置切点的方法声明中()内写入参数类型,并采用and字段连接参数名args(参数名1,参数名2),这里的参数名取决于在配置前置或后置通知里对参数的声明名称;

【2】对有参数的切点配置前置或后置通知时,需要在后面写上参数名arg-names=“设定参数名1,设定参数名2”,规则同上;

【3】切面的ref对应切面前置,后置对象方法所在的类

	<!-- 配置Aspect-J的通知对象 -->
	<aop:config>
		<aop:aspect ref="aspectJStyle">
			<!-- 配置切点 -->
			<aop:pointcut expression="execution(* 	com.testAOP.SchemaBased.demo.cutPoint1(String,int)) and args(name,age)"  id="pointCut1"/>	
			<aop:pointcut expression="execution(* 	com.testAOP.SchemaBased.demo.cutPoint3())" id="pointCut3"/>
			<aop:before method="myBefore" pointcut-ref="pointCut1" arg-	names="name,age"/>
			<aop:after method="myAfter" pointcut-ref="pointCut1" arg-names="name,age"/>
			<!--这种写法报错,如何写带参方法的环绕切面尚待解决
			 <aop:around method="mySurround2" pointcut-ref="pointCut1" arg-names="name,age"/>
			  -->
			<aop:around method="mySurround" pointcut-ref="pointCut3"/>
		</aop:aspect>
	</aop:config>

5.采取注解方式配置切面方法

(1)配置文件的编写;
	
	添加xmlns:context命名空间,代码如下:

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

	配置<context:component-scan>标签,用于扫描指定的类,内容为切点方法的完整类名

	添加的特殊代码:
	//这端代码的含义:设置Spring的cglib动态代理开启,cglib动态代理的原理是基于字节码生成真实对象的子类(类似于JDK动态代理模式)。需要导入的jar包有cglib和asm(解析字节码必须包)
	//由于代理类与真实类转换异常,因此需要设置动态代理开启
	<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>


	
(2)添加注解;
	
	【1】在修饰的切点类上添加@Component;切点方法上添加@PointCut(""),代表切点,其中""内部的写

		法与Spring AspentJ写法一致,即("execution(* 完整包名+方法名)");
	
	【2】在通知类上添加@Component与@Aspect;在具体的前置通知等通知方法上添加注解声明其通知类

		型。如@Before(""),""内部的写法为修饰的切点方法的完整名(完整包名+方法名)

6.自动注入的实现

1.在 Spring 配置文件中对象名和 ref=”id”id 名相同使用自动注入,可以不配置<property/>

2.两种配置办法
2.1 在<bean>中通过 autowire=”” 配置,只对这个<bean>生效
2.2 在<beans>中通过 default-autowire=””配置,表当当前文件中所
有<bean>都是全局配置内容

3.autowire=“” 可取值如下:

3.1 default: 默认值,根据全局 default-autowire=””值.默认全局和局部都没有配置情况下,相当于 no
3.2 no: 不自动注入
3.3 byName: 通过名称自动注入.在 Spring 容器中找类的 Id
3.4 byType: 根据类型注入. 
	3.4.1 spring 容器中不可以出现两个相同类型的<bean>
3.5 constructor: 根据构造方法注入.
 	3.5.1 提供对应参数的构造方法(构造方法参数中包含注入对
	戏那个)
	3.5.2 底层使用 byName, 构造方法参数名和其他<bean>的 id
相同.

7.注入配置文件的实现

1.在xml中编写的代码

注意导入dtd文件命名空间

<!-- 读取属性文件 -->
<context:property-placeholder location="classpath:db.properties"></context:property-placeholder>
<!-- Spring数据源封装,用于获取数据库连接 -->
<bean id="dataSource" class="org.springframework.jdbc.datasource.DriverManagerDataSource">
	<property name="driverClassName" value="${jdbc.driveclass}"></property>
	<property name="url" value="${jdbc.url}"></property>
	<property name="username" value="${jdbc.username}"></property>
	<property name="password" value="${jdbc.password}"></property>
</bean>	

2.测试类读取属性文件内容

@Value("${jdbc.username}")
private String Uname;

8.bean中对象的scope属性

作用:控制对象有效范围(单例,多例等)
1. <bean/>标签对应的对象默认是单例的  无论获取多少次,都是同一个对象
2. scope 可取值
2.1 singleton 默认值,单例
2.2 prototype 多例,每次获取重新实例化
2.3 request 每次请求重新实例化
2.4 session 每个会话对象内,对象是单例的. 
4.5 application 在 application 对象内是单例
2.6 global session spring推出的一个对象, 依赖于spring-webmvc-portlet ,类似于 session

9.声明式事务

//注意导入相关的dtd代码
 <!-- 实例化要声明事务的业务类 -->
<bean id="fooService" class="x.y.service.DefaultFooService"/>

<!--配置事务相关信息,如事务回滚,事务提交等 -->
<tx:advice id="txAdvice" transaction-manager="txManager">
    <!-- the transactional semantics... -->
    <tx:attributes>
        <!-- 特定方法配置事务,并带有特定的事务属性 -->
        <tx:method name="get*" read-only="true"/>
        <!-- 其他方法不配置特定属性时 可以采用通配符表示 -->
        <tx:method name="*"/>
    </tx:attributes>
</tx:advice>

<!--定义切点,切点的定义广度应该适量的大,保证事务的配置能作用于此切点内的方法 -->
<aop:config>
    <aop:pointcut id="fooServiceOperation" expression="execution(* x.y.service.FooService.*(..))"/>
    <aop:advisor advice-ref="txAdvice" pointcut-ref="mypoint"/>
</aop:config>

<!--数据源的使用-->
<bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
    <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
    <property name="url" value="jdbc:mysql://localhost/stuinfo"/>
    <property name="username" value="root"/>
    <property name="password" value="root"/>
</bean>

<!-- 事务管理对象的使用 -->
<bean id="txManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
    <property name="dataSource" ref="dataSource"/>
</bean>
  • 10:事务相关知识
  1. propagation 控制事务传播行为. 当一个具有事务控制的方法被另一个有事务控制的方法调用后,需要如何管理事务(新建事务?在事务中执行?把事务挂起?报异常?)

    1. REQUIRED (默认值): 如果当前有事务,就在事务中执行,如果当前没有事务,新建一个事务.
    2. SUPPORTS:如果当前有事务就在事务中执行,如果当前没有事务,就在非事务状态下执行.
    3. MANDATORY:必须在事务内部执行,如果当前有事务,就在事务中执行,如果没有事务,报错.
    4. REQUIRES_NEW:必须在事务中执行,如果当前没有事务,新建事务,如果当前有事务,把当前事务挂起.
    5. NOT_SUPPORTED:必须在非事务下执行,如果当前没有事务,正常执行,如果当前有事务,把当前事务挂起.
    6. NEVER:必须在非事务状态下执行,如果当前没有事务,正常执行, 如果当前有事务,报错.
    7. NESTED:必须在事务状态下执行.如果没有事务,新建事务,如果当前有事务,创建一个嵌套事务.
  2. isolation=”” 事务隔离级别

    1 在多线程或并发访问下如何保证访问到的数据具有完整性的.

    1.1 脏读: 一个事务(A)读取到另一个事务(B)中未提交的数据,此时A事务读取的数据可能和数据库中数据是不一致的,此时认为数据是脏数据,读取脏数据过程叫做脏读.

    1.2 不可重复读:

     1.2.1主要针对的是某行数据.(或行中某列)
     1.2.2 主要针对的操作是修改操作. 
     1.2.3 两次读取在同一个事务内
     1.2.4 当事务 A 第一次读取事务后,事务 B 对事务 A 读取的数据进行修改,事务 A 中再次读取的数据和之前读取的数据不一致,过程不可重复读. 
    

    1.3 幻读:

     1.3.1主要针对的操作是新增或删除
     1.3.2 两次事务的结果. 
     1.3.3 事务 A 按照特定条件查询出结果,事务 B 新增了一条符合条件的数据.事务 A 中查询的数据和数据库中的数据不一致的,事务 A 好像出现了幻觉,这种情况称为幻读. 
    

    1.4 DEFAULT: 默认值,由底层数据库自动判断应该使用什么隔离界别

     1.4.1 READ_UNCOMMITTED: 可以读取未提交数据,可能出现脏读,不重复读,幻读. (效率最高). 
     1.4.2 READ_COMMITTED:只能读取其他事务已提交数据.可以防止脏读,可能出现不可重复读和幻读.(oracle默认) 
     1.4.3 REPEATABLE_READ: 读取的数据被添加锁,防止其他事务修改此数据,可以防止不可重复读.脏读,可能出现幻读. (mysql默认)
     4.9 SERIALIZABLE: 排队操作,对整个表添加锁.一个事务在操作数据时,另一个事务等待事务操作完成后才能操作这个表.(最安全的但是效率最低)
    

    1.5 rollback-for=”异常类型全限定路径”

     1.5.1 当出现什么异常时需要进行回滚
     1.5.2 建议:给定该属性值. 
     1.5.3 手动抛异常一定要给该属性值. 
    

    1.6 no-rollback-for=”” (当出现什么异常时不滚回事务)

11.Spring的常用注解

  • @Component 创建类对象,相当于配置
  1. @Service 与@Component 功能相同. 写在 ServiceImpl 类上.

  2. @Repository 与@Component 功能相同. 3.1 写在数据访问层类上.

  3. @Controller 与@Component 功能相同. 4.1 写在控制器类上.

  4. @Resource(不需要写对象的 get/set)

    5.1 java 中的注解

    5.2 默认按照 byName 注入,如果没有名称对象,按照 byType 注入

    5.2.1 建议把对象名称和 spring 容器中对象名相同

  5. @Autowired(不需要写对象的 get/set)

    6.1 spring 的注解

    6.2 默认按照 byType 注入. 7. @Value() 获取 properties 文件中内容

  6. @Pointcut() 定义切点

  7. @Aspect() 定义切面类

  8. @Before() 前置通知

  9. @After 后置通知

  10. @AfterReturning 后置通知,必须切点正确执行

  11. @AfterThrowing 异常通知

  12. @Arround 环绕通知

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值