Spring Framework笔记

https://www.cnblogs.com/s648667069/p/6513335.html

https://blog.youkuaiyun.com/JIESA/article/details/78094677

https://blog.youkuaiyun.com/silyvin/article/details/70832415

https://blog.youkuaiyun.com/u013399093/article/details/54922902

https://blog.youkuaiyun.com/kirrin/article/details/47831845

http://www.icoolxue.com/album/show/158

http://edu.51cto.com/course/11708.html

https://blog.youkuaiyun.com/xunbaogang/article/details/52071532

https://blog.youkuaiyun.com/u013399093/article/details/54922902

https://blog.youkuaiyun.com/xiaohe958/article/details/49177615

待整理。。。

1. Bean的定义一定要有无参构造函数,先通过反射调用无参构造函数,再set属性。

2. <property name="xxxx" value = "yyy"/> xxx与setXXX()函数对应。

3. ApplicationContext:IOC容器,只有IOC容器初始化后才可以用于创建Bean,Spring提供两种容器,BeanFactory和ApplicationContext,前者面向Spring,后者面向用户,基本使用后者。

ApplicationContext继承关系:    

    |——ConfigurableApplicationContext 

            新加两个方法:refresh(), close()让ApplicationContext具有启动,刷新,关闭上下文的能力

           |—— ClassPathXMLApplicationContext:类路径下加载容器

           |——FileSystemXMLApplicationContext

 getBean()方法是由BeanFactory提供,ApplicationContext继承BeanFactory

4. 参数注入两种该方式:<property name="" value=""> <constructor-arg value="" index=x type="int"> 后者通过index或type来指定调用什么构造函数

    一些细节:

<constructor-arg type="int">
   <value>1</value>
   <index>1</index>
<constructor-arg/>
  • 字面值:可以用字符串表示的值,可以通过<value>元素标签或value属性进行注入
  • 基本数据类型及其封装、String等类型都可以用字面值注入的方式
  • 若字面值中包含特殊字符,可以使用<![DCATA[]]>把字面值包裹起来。比如下面这个代码value的值为“<shanghai>”
<constructor-arg>
   <value><![CDATA[<shanghai>]]></value>
</constructor-arg>

5. Bean的相互引用

<bean id="person" class="com.person">
   <property name="name" value="tom"/>
   <property name="owningCar" ref="car2" />
</bean>
<bean id="person" class="com.person">
    <property name="owningCar">
        <ref bean="car2"/>
    </property>
</bean>
6. 内部Bean
<bean id="person" class="com.person">
   <property name="name" value="tom"/>
   <property name="owningCar">
       <bean id="aCar" class="com.car">
           <constructor-arg value=""/>
           ...
       </bean>
   </property>
</bean>

内部Bean可以不写Id,因为不可以被外部引用的。内部Bean也可以定义在constructor-arg的value属性里

7. 参数注入的null和级联参数:

    null专有标记:<nulll/> 其实不赋值就是null

    级联参数<constructor-arg ref="car2"/> <property name="car.maxSpeed" value=120/>

    集合属性:<list><set>元素可以是<value><ref>或<bean>内部bean ,<map>的内部元素是<entry>  

<property name="cars">
   <list>
     <ref bean="car1"/>
     <ref bean="car2"/>
   </list>
</property>
<property name="cars">
   <map>
       <entry key="A" value-ref="car1"/>
   </map>
</property>

将集合配成一个Bean,共多个property使用

<!--需要导入util命名空间-->
<util:list id="cars">
    <ref bean="car1"/>
    <ref bean="car2"/>
</util:list>

<!--如何使用-->
<property name="cars" ref="cars">
</property>

8. <props>是<map>的子类,专用来为Properties类型属性赋值

public class DataSource {

 priavte Properties properties;

 ...get set
}
<bean id="dataSOurce" class="com.DataSource">
 <property name="properties">
    <props>
        <prop key="user">li</prop>
        <prop key="age">2</prop>
    </props>
 </bean>   
</bean>

9. 使用P命名空间为bean的属性赋值,需要先导入P命名空间。相对于传统的配置方式更加简洁。

<bean id="person" class="com.person" p.name="tom" p.age=20 p.cars-ref="cars"/>

10. 自动装配

在autowire属性指定自动装配模式:(1)byType (2)byName (3)byConstructor不推荐

<bean id="person" class="com.person" autowire="byName">

<!--byname要求插入的bean的名字和被插入的对象的setter风格的属性名一致-->

缺点:(1)所有属性要么都用,要么都不用autowire (2)byName,byType不可以混合使用

11. Bean的继承(配置继承)

<bean id="person1" class="com.person" p:age=10 p:name="tom"/>

<bean id="person2" class="com.person" parent="person1" name="jerry"/>

子Bean可以继承和覆盖父Bean的属性。

父Bean可以配置为实例或模板,模板不可以被实例化,举例:

<bean id="person" class="com.person" p:name="tom" abstract="true"/>

如果一个Bean的class属性没有指定,那么他必须是模板Bean

<bean id="template" p:name="tom" abstract="true"/>

12. 指定Bean的前置依赖

<bean id="" class="" depends-on="anotherBeanId"/>

前置依赖Bean会在这个Bean之前创建好,如果依赖到多个前置依赖Bean,则用逗号空格的方式设置Bean的名称。

13. Bean的作用域

Singleton:单例,容器初始化时创建

Prototype

14. 使用外部属性文件

应用背景:有时需要在Bean的配置里混入系统部署的细节信息,如文件路径等,而这些部署细节实际上需要和Bean配置相分离。

原理:Spring提供了一个PropertyPlaceholderConfiguregurer的BeanFactory后置处理器,这个处理器允许用户将Bean配置的部分内容外移到属性文件中。可以在Bean配置文件里使用${value}的变量,PropertyPlaceholderConfigurer从属性文件里加载属性,并使用这些属性来替换变量。

Spring还允许使用${propName},以实现属性之间的相互引用。

导入context命名空间<>
导入配置文件:
<context:property-placeholder location="classpath:db.properties"/>
使用外部变量名:
<property name="user" value="${aUserName}">

15. Spring表达式语言:SpEL

待整理

16. IOC容器中Bean的生命周期

IOC容器对Bean的生命周期进行管理的过程:

- 通过构造函数或工厂方法创建Bean的实例 ->constructor

- 为Bean的属性设置值和对其他Bean的引用 -> setXXX()

- 调用Bean的初始化方法 ->init-method

- Bean可以使用了

- 当关闭容器时,调用Bean的销毁方法 ->destory-method

16.1 使用init-method 和 destory-method

在Bean的声明里设置init-method和destory-method属性,为Bean指定初始化方法和销毁方法

<!--initCar destoryCar-->
<bean id="car" class="com.car" init-method="initCar" destory-method="destoryCar">
    <property ...>
</bean>
PS:关闭容器使用ConfigurableApplicationContext.close() 方法


16.2 Bean后置处理器

Bean后置处理器允许在调用初始化方法前后对Bean进行额外的处理。 Bean后置处理器对IOC容器里的所有Bean实例逐一处理,而非针对单一实例。典型应该用是Bean属性的正确性或根据特定的标准更改Bean的属性。

要使用后置处理器,需要类实现org.springframework.beans.factory.config.BeanPostProcessor接口。在初始化方法被调用前后,Spring把每个Bean实例分别传递给上述接口的以下两个方法:

postProcessAfterInitialization(Object bean, String beanName);

postProcessBeforeInitialization(Object bean, String beanName);

在使用后置处理其之后,生命周期就变成:

- 通过构造函数或工厂方法创建Bean的实例 ->constructor

- 为Bean的属性设置值和对其他Bean的引用 -> setXXX()

- 将Bean实例传递给Bean后置处理器的postProcessBeforeInitialzation()

- 调用Bean的初始化方法 ->init-method

- 将Bean的实例传递给Bean后置处理器的postProcessAfterInitialization()

- Bean可以使用了

- 当关闭容器时,调用Bean的销毁方法 ->destory-method


使用:1定义public class MyBeanPostProcessor implements BeanPostProcessor;

2.声明Bean<bean class="com.MyBeanPostProcessor" > 不需要配置id,IOC容器自动识别是一个BeanPostProcesstor,这个Bean对每一其他的Bean都起作用,我们可以在MyBeanPostProcessor的代码逻辑里进行过滤。

17. 通过工厂方法配置Bean (创建Bean的第二种方法)

工厂方法分为静态工厂方法和实例工厂方法:

静态工厂方法:将对象创建的过程封装到静态方法中,当用户需要对象的时候,只需要简单的调用静态方法,而不用关心创建的细节。要声明通过静态方法创建的Bean,需要在Bean的class属性里指定拥有该工厂的方法的类,同时咋ifactory-method属性里指定工厂方法的名称,最后使用<contructor-arg>元素为该方法传递方法参数。

public class Car {
   public Car(...)
}

//静态工厂方法:直接调用某一个类的静态方法,就可以返回Bean的实例
public  class StaticCarFactory {
    private static Map<String, Car> cars = new HashMap<>();
    public static Car getCar(String name) {
        return cars.get(name);
    }

}
<!--通过静态工厂方法来配置Bean,注意不是配置静态工厂方法实例,而是配置Bean实例, class属性只想静态工厂方法的类名,factory-method指向方法名,constructor-arg指定工厂方法的参数-->
<bean id="car" class="com.StaticCarFatory" factory-method="getCar">
   <constructor-arg value="audi"/>
</bean>

实例工厂方法:不是通过静态方法,是通过一个实例工厂类的方法构造。

// 实例工厂方法:实力工厂的方法,需要创建工厂本身的实例,再调用工厂的方法来放回Bean的实例
pulic class InstanceCarFactory {	
	private Map<String, Car> cars = new HashMap<>();
		public InstanceCarFactory() {
			car.put("audi", new Car(...));			
		}		
		public Car getCar(String brand) {			
			return car.get(brand);		}
}
<!--现声明工厂的实例-->
<bean id="carFactory" class="com.InstanceCarFactory">
</bean>
<!--再声明被创建的Bean-->
<bean id="car" factory-bean="carFactory" factoyMethod="getCar">
    <constructor-arg value="audi"/>
</bean>
18 通过FactoryBean创建Bean (创建Bean的第三种方式)
public class CarFactoryBean implements FactoryBean<Car>{
	private String brand; public void setBrand(String brand){...}
	@Override
	public Car getObject() throws Exception {		
		return new Car(...);
	}
	
	@Override
	public Class<?> getObjectType() {
		return Car.class;		
	}
	
	@Override
	public boolean isSingleton() {
		return true;		
	}
}
<bean id="car" class="com.CarFactoryBean">
  <property name="brand" value="BMW"/>
</bean>

19. 通过注解

    19.1使用注解配置Bean

     -组件能够在classPath下扫描和实例化具有特定注解的组件

    - 特定注解有:Component(通用组件) Controller(建议放在表现层)Service(建议放在服务层)Repository(建议放在持久层)。其实可以混用,因为Spring无法区分具体Bean是在哪个层。

    - Bean的命名:默认是类名(第一个字母小写),也可以通过Value属性指定 @Component(value="xxx")

    - 还需要配置Context component scan

<!--先要引入context命名空间-->
<context:component-scan base-package="com.test"/>

会扫描指定包及其子包。还有一个属性resource-pattern设定只扫描指定的类,比如:

resource-pattern="repository/*.class" 会指定只扫描com.test.repository包下的类

context:component-scan还有两种子节点<context:include-filter><context:excludefilter>

<context:exclude-filter type="annotation" expression="[Controller的全类名]"/>

上面表明exclude掉controller标记的类。

常见的type取值,前两种比较常用

类别示例说明
annotationcom.atgulug.xxxAnnotation所有标注了xxxAnnotation的类
assinablecom.atgulug.xxxService所有继承或扩展xxxService的类
aspectjcom.atgulug...*Service+所有类名以Service结束的类及继承或扩展他们的类。该类型采用AspectJ表达式进行过滤
regexcom.\atguigu\.anno\.*所有com.atguigu.anno包下的类。该类型通过正则表达式进行类过滤
customcom.atguigu.xxxTypeFilter采用xxxTypeFilter通过代码的方式定义过滤规则。该类必须实现org.springframework.core.type.TypeFilter接口

20 自动装配

<context:component-scan>元素还会自动注册 AutowiredAnnotationBeanPostProcessor实例,该实例可以自动装配具有@Autowired @Resource @Inject注解的属性

@Autowired可以放在构造函数,普通字段,以及任何有参数的地方。自动装配类型兼容的Bean

@Autowired(required=false)可以在没有对应的时候注入null

如何处理有多个匹配?@Autowired@Qualifier("name")指定要名为name的Bean

也可以加到入参的前面:

void setCar(@Qualifier("name") Car car)

@Autowired还可以放在list/set/map:对list IOC会将所有满足条件的都装配进去,对set IOC读取该集合的类型信息,然后装配所有满足类型的Bean;对于map,IOC会将Bean的名称作为键

@Resource注解要求提供一个Bean名称的属性,若该属性为空,则自动采用标注处的变量或方法名称作为Bean的名称

@Inject和@Autowired一样,但没有required属性

21. AOP术语

切面(Aspect):横切关注点(跨越应用多个模块功能)被模块化的特殊对象

通知(Advice):切面必须要完成的工作

目标(Target):   被通知的对象

代理(Proxy): 向目标对下个应用通知之后创建的对象

连接点(JointPoint):程序执行的某个特定位置:如类的某个方法调用前、调用后、方法抛出异常后等。连接点有两个信息确定:方法表示的程序执行点;相对点表示方位。例如ArithmaticCalculator#add()方法执行前的连接点,执行点为ArithmaticCalculator#add();方位为该方法执行前的位置。

切点(pointcut):每个类都拥有多个连接点:例如ArithmeticCalculator的所有方法实际上都是连接点,即连接点是程序类中客观存在的事务。AOP通过切点定位到特定的连接点。类比:连接点相当于数据库中的记录,切点相当于查询条件。切点和连接点不是一对一的关系,一个切点匹配多个连接点,切点通过org.springframework.aop.Pointcut接口进行描述,它使用类和方法作为连接点的查询条件。

22. AspectJ

import org.aspectj.lang.annotation.Aspect
import org.springframework.stereotype.Component

// 把该类声明为一个切面:需要把该类放到IOC容器中,再声明为一个切面
@Aspect
@Component
public class LoggingAspect {
	
	//声明该方法是一个前置advice:在目标方法之前执行
	@Before("execution(public int com.atguigu.ArithmeticCalculation.*(int, int))")
	public void beforeMethod(JoinPoint joinpoint) {
		String methodName = joinpoint.getSigniture().getName();
		List<Object> args = Arrays.asList(joinpoint.getArgs());
		System.out.println("The method begins" + methodName +"begins with " + args);
	}
	
	@AfterReturning(value = "execution(public int com.atguigu.ArithmeticCalculation.*(int, int))", returning = "result")
	public void afterReturning(Jointpoint joinpoint, Object result) {
		System.out.println("result is " + result);
	}
	
	@AfterThrowing(value = "execution(public int com.atguigu.ArithmeticCalculation.*(int, int))", throwing="ex") 
	public void afterThrowing(Jointpoint joinpoint, Exception ex) {
	
	}
	
	// 只有空指针异常才会触发这个方法
	@AfterThrowing(value = "execution(public int com.atguigu.ArithmeticCalculation.*(int, int))", throwing="ex") 
	public void afterNullThrowing(Jointpoint joinpoint, NullPointException ex) {
	
	}
	
	// 环绕通知需要携带ProceedingJoinpoint类型的参数
	// 环绕通知类似于动态代理的全过程: ProceedingJoinpoint参数可以决定是否执行目标方法
	// 且环绕通知必须要有返回值,返回值即为目标方法的返回值
	@Around("execution(public int com.atguigu.ArithmeticCalculation.*(int, int))")
	public int aroundMethod(ProceedingJoinpoint joinpoint) {
		System.out.println("around method");
		Object result = null;
		
		try {
			// 前置通知
			System.out.println("before proceed");
			// 执行目标方法
			result = joinpoint.proceed();
			// 后置通知
			System.out.println("after proceed");
		} catch(Exception e) {
			// 通知
			System.out.println("after exception");
			
		}
		// 后置通知
		System.out.println("method end");
		return result;
		
	}	
}

<!--使切面的Before注解起作用(起作用的原理是:Spring自动为匹配的目标方法所在的类创建一个代理)-->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>

  (1) 加依赖包

(2)xml导入aop命名空间

(3)基于主借的方式

     ① 在配置文件中配置aop:aspectj-proxy

    ② 把横切关注点的代码抽象到一个切面类。ps:切面首先是一个Component,切面还需要加入@Aspect注解

    ③ 在类中声明各种通知:一个通知就是一个方法,声明通知类型包括:@Before,@After(无论该方法发生异常,且后置通知不能够访问到目标方法返回的结果,如果需要访问返回结果,需要使用返回通知),@AfterRunning, @AfterReturning(返回通知,发生在后置通知之后),@AfterThrowing,@Around。并需要指定切入点表达式

“execute(public void com.test.method(int, int))”
当执行public void com.test.method(int, int)方法时
“execute(* com.test.method(int, int))”
当执行任意修饰符,任意返回值,但方法名和参数列表匹配的方法的时候
“execute(public void com.test.*(int, int))”
当执行com.test类中任意方法,且参数类型,修饰符和返回值类型满足的方法
“execute(public double com.test.*(double, ..))”第一个参数为double型,.. 表示陪陪任意数量任意类型的参数




注意:com.test.method()如果是一个接口方法,那么这个通知会对所有这个接口的实现类的method()方法起作用。

④ 通知方法可以包含Jointpint类型的参数。

24. 切面的优先级

@Order

25. 重用切点表达式:

①:声明

@Pointcut("execute....")

public void declarePointcut();

②:使用

@Before("declarePointcut()") //如果是在不同的包,需要用"全类名.方法名()"

public void method()

26. 事务

  • 事务管理是用来确保数据的完整性和一致性。
  • 事务就是一系列动作,他们被当作一个独立的工作单元,这些动作要么全部完成,要么全部不起作用。
  • 事务的四个关键属性(ACID) :① 原子性(Atomicity)事务是原子的,确保事务要么都完成,要么都不完成 ②. 一致性(consisitency)一旦所有事务动作完成,事务就被提交,数据和资源就处于一种满足业务规则的一致状态中 ③.隔离性(isolation)可能有许多事务会同时处理相同的数据,因此每个事务都应该与其他事务隔离开来,防止数据破坏(四种隔离级别:https://blog.youkuaiyun.com/qq_33290787/article/details/51924963) ④.持久性(durability)一旦事务完成,无论发生什么系统错误,它的结果都不应该受到影响。通常情况下,事务的结果被写到持久化存储中。
  • 事务的传播行为:一个事务方法被另一个事务方法调用时,必须指定事务应该如何传播。例如:方法可能继续在现有的事务中运行,也可能开启另一个新的事务,并在自己的事务中运行。 @Transactional(propagation=Propagation.REQUIRED)

传播属性描述
REQUIRED如果有事务运行,那么就用这个事务,否则就新建一个,并在自己的事务中运行
REQUIRED_NEW一定新开一个
SUPPORTS如果有事务运行,则当前方法运行在这个事务中,否则不运行在任何事务中。
NOT_SUPPORTED当前方法不运行在事务中,如果当前有运行的事务,则将该事务挂起。
MANDATORY当前方法必须运行在事务中,如果没有事务,则抛出异常。
NEVER当前事务不应该运行在事务中,如果当前有事务,则抛出异常
NESTED如果有事务在运行,当前的你发给发就应该在这个事务的嵌套事务内运行。否则就启动一个新的事务,并在他自己的事务中运行
public interface BookshopDao {

	int findBookPriceByIsbn(String isbn);
	// 更新库存-1
	void updateBookStock(String isbn);
	void updateUserAccount(String userName, int price);

}

@Repository("bookShopDao")
public class BookshopDaoImp implments BookshopDao {

	@Autowired
	private JdbcTemplate jdbcTemplate;
	
	@Override
	int findBookPriceByIsbn(String isbn){
		jdbcTemplate.queryForObject(...);
	}
	// 更新库存-1
	@Override
	void updateBookStock(String isbn){
		// 若库存不够,抛出异常
		int stock = jdbcTemplate.queryForObject(...);
		if (stock == 0) {
			throw new RuntimeException();
		}
		jdbcTemplate.update(...);
	}
	@Override
	void updateUserAccount(String userName, int price){
		// 若余额不够,抛出异常
		int balance = jdbcTemplate.queryForObject(...);
		if (balance == 0) {
			throw new RuntimeException();
		}
		jdbcTemplate.update(...);
	}
}

@Service
public  class BookshopService {

	@Autowired
	private BookshopDao bookShopDao;
	
	@Transactional
	public void purchase(String userName, String isbn) {
		int price = bookShopDao.findBookPriceByIsbn(isbn);
		bookShopDao.updateBookStock(isbn);
		bookShopDao.updateUserAccount(userName, price);
	}
}
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
	<property name="dataSource" ref="dataSource"/>
</bean>
<!--启动注解事务-->
<tx:annotation-driven transaction-manager="transactionManager"/>










评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值