目录
1.注解/Annotation和xml
1.1DI相关
@Autowired可以单独使用,用于依赖注入的时候使用(DI)。
如果单独使用,则按类型连接(wired by type)。因此,如果容器中声明了多个相同类型的bean,就会出现问题,因为@Autowired不知道使用哪个bean来注入。因此,使用@Qualifier和@Autowired来通过指定bean名字(通过名字来连接)来明确哪些bean需要被连接。
@Resource也是通过名称连接的,所以如果@Autowired和Qualifier一起使用,它和@Resource是一样的。
区别在于@Autowired和@Qualifier是spring注解,而@Resource是标准的java注解(来自JSR-250)。此外,@@Resource只支持字段和setter注入,而@Autowired支持字段、setter、构造函数和多参数方法注入。
建议对字段和setter注入使用@Resource,对于构造函数或者多参数方法注入,坚持使用@Qualifier和@Autowired
1.2动态代理
JDK的动态代理

package cn.itcast.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
public class ProxyTest {
public static void main(String[] args) {
//1.创建真实对象
Lenovo lenovo = new Lenovo();
//2.动态代理增强lenovo对象
/*
三个参数:
1. 类加载器:真实对象.getClass().getClassLoader()
2. 接口数组:真实对象.getClass().getInterfaces()
3. 处理器:new InvocationHandler()
*/
SaleComputer proxy_lenovo = (SaleComputer) Proxy.newProxyInstance(lenovo.getClass().getClassLoader(), lenovo.getClass().getInterfaces(), new InvocationHandler() {
/*
代理逻辑编写的方法:代理对象调用的所有方法都会触发该方法执行
参数:
1. proxy:代理对象
2. method:代理对象调用的方法,被封装为的对象
3. args:代理对象调用的方法时,传递的实际参数
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/*System.out.println("该方法执行了....");
System.out.println(method.getName());
System.out.println(args[0]);
*/
//判断是否是sale方法
if(method.getName().equals("sale")){
//1.增强参数
double money = (double) args[0];
money = money * 0.85;
System.out.println("专车接你....");
//使用真实对象调用该方法
String obj = (String) method.invoke(lenovo, money);
System.out.println("免费送货...");
//2.增强返回值
return obj+"_鼠标垫";
}else{
Object obj = method.invoke(lenovo, args);
return obj;
}
}
});
//3.调用方法
/* String computer = proxy_lenovo.sale(8000);
System.out.println(computer);*/
proxy_lenovo.show();
}
}
cglib动态代理

1.3AOP(切面编程)
1.3.1XML配置

1.3.2注解开发



1.4Jdbc



2.Spring配置注解
2.1@Configuration的使用
@Configuration用于定义配置类,可以替换xml配置文件,被注解的类内部包含有一个或者多个被@Bean注解的方法,这些方法将会AnnotationConfigApplicationContext或者AnnotationConfigWebApplicationContext类进行扫描,并用于构建bean定义,初始化Spring容器。
注意:@Configuration注解的配置类由如下要求:
1.@Configuration不可以是final类型;
2.@Configuration不可以是匿名类;
3.嵌套的configuration必须是 静态类;
2.1.1用@Configuration加载Spring
2.1.1.1@Configuration配置Spring并启动Spring容器
@Configuration标注在类上,相当于把该类作为Spring的xml配置文件中的<beans>,作用为:配置Spring容器(应用上下文)
package com.dxz.demo.configuration;
import org.springframework.context.annotation.Configuration;
@Configuration
public class TestConfiguration {
public TestConfiguration() {
System.out.println("TestConfiguration容器启动初始化。。。");
}
}
相当于
<?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:context="http://www.springframework.org/schema/context" xmlns:jdbc="http://www.springframework.org/schema/jdbc"
xmlns:jee="http://www.springframework.org/schema/jee" xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:util="http://www.springframework.org/schema/util" xmlns:task="http://www.springframework.org/schema/task" xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans-4.0.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context-4.0.xsd
http://www.springframework.org/schema/jdbc http://www.springframework.org/schema/jdbc/spring-jdbc-4.0.xsd
http://www.springframework.org/schema/jee http://www.springframework.org/schema/jee/spring-jee-4.0.xsd
http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx-4.0.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util-4.0.xsd
http://www.springframework.org/schema/task http://www.springframework.org/schema/task/spring-task-4.0.xsd" default-lazy-init="false">
</beans>
主方法进行测试:
package com.dxz.demo.configuration;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
public class TestMain {
public static void main(String[] args) {
// @Configuration注解的spring容器加载方式,用AnnotationConfigApplicationContext替换ClassPathXmlApplicationContext
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfiguration.class);
// 如果加载spring-context.xml文件:
// ApplicationContext context = new
// ClassPathXmlApplicationContext("spring-context.xml");
}
}
从运行主方法结果可以看出,spring容器已经启动了:

2.1.1.2@Configuration启动容器+@Bean注册Bean
@Bean标注在方法上(返回某个实例的方法),等价于spring的xml配置文件中的<bean>,作用为:注册bean对象。
Bean类:
/**
* @author chenzeyu
*/
public class TestBean {
private String username;
private String url;
private String password;
public void sayHello() {
System.out.println("TestBean sayHello...");
}
@Override
public String toString() {
return "username:" + this.username + ",url:" + this.url + ",password:" + this.password;
}
public void start() {
System.out.println("TestBean 初始化。。。");
}
public void cleanUp() {
System.out.println("TestBean 销毁。。。");
}
}
配置类:
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
/**
* @author chenzeyu
*/
@Configuration
public class TestConfiguration {
public TestConfiguration(){
System.out.println("TestConfiguration容器初始化...");
}
//@Bean注解注册bean,同时可以指定初始化和销毁方法
//@Bean(name="testBean",initMethod="start",destroyMethod="cleanUp")
@Bean
public TestBean testBean() {
System.out.println("testBean");
// instantiate, configure and return bean ...
return new TestBean();
}
@Bean
public void Hello(){
System.out.println("Hello");
}
}
主方法测试类:
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;
/**
* @author chenzeyu
*/
public class TestMain {
public static void main(String[] args){
//@Configuration注解的spring容器加载方式,用AnnotationConfigApplicationContext替换ClassPathXmlApplicationContext
ApplicationContext context =new AnnotationConfigApplicationContext(TestConfiguration.class);
//如果加载Spring-context.xml文件:
//ApplicationContext context = new ClassPathXmlApplicationContext("spring-context.xml");
//获取Bean
TestBean tb = (TestBean) context.getBean("testBean");
tb.sayHello();
}
}

注:
(1)、@Bean注解在返回实例的方法上,如果未通过@Bean指定bean的名称,则默认与标注的方法名相同。
(2)、@Bean注解默认作用域为单例singleton作用域,可通过@Scope("prototype")设置为原型作用域;
(3)、既然@Bean的作用是注册bean对象,那么完全可以使用@Compontent、@Controller、@Service、@Repository等注解注册Bean,当然需要配置@ComponentScan注解进行自动扫描。
2.1.1.3@Configuration启动容器+@Component注册Bean
Bean类:
package com.dxz.demo.configuration;
import org.springframework.stereotype.Component;
//添加注册bean的注解
@Component
public class TestBean {
private String username;
private String url;
private String password;
public void sayHello() {
System.out.println("TestBean sayHello...");
}
public String toString() {
return "username:" + this.username + ",url:" + this.url + ",password:" + this.password;
}
public void start() {
System.out.println("TestBean 初始化。。。");
}
public void cleanUp() {
System.out.println("TestBean 销毁。。。");
}
}
2.1.1.4使用AnnotationConfigApplicationContext注册AppContext类的两种方法
(1)配置类的注册方式是将其传递给AnnotationConfigApplicationContext构造函数
public static void main(String[] args) {
// @Configuration注解的spring容器加载方式,用AnnotationConfigApplicationContext替换ClassPathXmlApplicationContext
ApplicationContext context = new AnnotationConfigApplicationContext(TestConfiguration.class);
//获取bean
TestBean tb = (TestBean) context.getBean("testBean");
tb.sayHello();
}
(2)AnnotationConfigApplicationContext的register方法传入配置类来注册配置类
public static void main(String[] args) {
ApplicationContext ctx = new AnnotationConfigApplicationContext();
ctx.register(AppContext.class)
}
2.1.1.5配置Web应用程序(web.xml中配置AnnotationConfigApplicationContext)
过去,您通常利用XmlWebApplicationContext上下文来配置Spring Web应用程序,即在Web部署描述符文件Web.xml中指定外部XML上下文文件的路径。XMLWebApplicationContext是Web应用程序使用的默认上下文类。以下代码描述了web,xml中指向将由ContextLoaderListener监听器类载入的外部XML上下文文件的元素。
<web-app>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>/WEB-INF/applicationContext.xml</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>sampleServlet</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
</servlet>
...
</web-app>
现在,您要将web.xml中的上述代码更改为使用ApplicationConfigApplicationContext类。切记XmlWebApplicationContext是Spring为Web应用程序使用的默认上下文实现,因此您永远不必在您的web.xml文件中显示指定这个上下文类。现在,您将使用基于Java的配置,因此在配置Web应用程序时,需要在web.xml文件中指定AnnotationConfigApplicationContext类。上述代码修改如下:
<web-app>
<context-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.
support.AnnotationConfigWebApplicationContext
</param-value>
</context-param>
<context-param>
<param-name>contextConfigLocation</param-name>
<param-value>
demo.AppContext
</param-value>
</context-param>
<listener>
<listener-class>
org.springframework.web.context.ContextLoaderListener
</listener-class>
</listener>
<servlet>
<servlet-name>sampleServlet</servlet-name>
<servlet-class>
org.springframework.web.servlet.DispatcherServlet
</servlet-class>
<init-param>
<param-name>contextClass</param-name>
<param-value>
org.springframework.web.context.
support.AnnotationConfigWebApplicationContext
</param-value>
</init-param>
</servlet>
...
</web-app>
以上修改后的web.xml定义了AnnotationConfigWebApplicationContext上下文类,并将其作为上下文参数和servlet元素的一部分。上下文配置现在指向AppContext配置类。
2.1.1.6@Configuration总结
@Configuration等价于<Beans></Beans>
@Bean等价于<Bean></Bean>
@ComponentScan等价于<context:component-scan base-package="com.dxz.demo"/>
https://docs.spring.io/spring-framework/docs/current/javadoc-api/org/springframework/context/annotation/Configuration.html
ConfigurationProperties
2.2@ConfigurationProperties的使用
官方文档建议将配置属性隔离到单独的pojo中。
@Configuration
@ConfigurationProperties(prefix="mail")
public class ConfigProperties{
private String hostName;
private int port;
private String from;
// standard getters and setters
}
我们使用@Configuration,这样Spring就可以在应用程序上下文中创建一个Spring Bean。
@ConfigurationProperties最适合使用具有相同前缀的层次属性,因此,我们添加一个mail前缀。
Spring框架使用标准的Java bean setters,因此我们必须为每个属性声明setter。
注意:如果我们在POJO中不使用@Configuration,那么我们需要在main Spring application class中添加@EnableConfigurationProperties(ConfigProperties.class),以将属性绑定到POJO中。
@SpringBootApplication
@EnableConfigurationProperties(ConfigProperties.class)
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
就是这样,Spring将自动绑定属性文件中定义的任何属性,这些属性具有前缀mail,并且与ConfigProperties类中的一个字段同名。
2.2.1Spring Boot 2.2
从Spring Boot2.2开始,Spring通过类路径扫描来查找和注册@ConfigurationProperties类。因此,不需要使用@Component(和其它元注释,如@Configuration)注释这样的类,甚至不需要使用@EnableConfigurationProperties
@ConfigurationProperties(prefix = "mail")
public class ConfigProperties {
private String hostName;
private int port;
private String from;
// standard getters and setters
}
由@SpringBootApplication启用的类路径扫描器会找到ConfigProperties类,尽管我们没有使用@Component注释这个类。
除此之外,我们可以使用@ConfigurationPropertiesScan注释来扫描配置属性类的自定义位置。
@SpringBootApplication
@ConfigurationPropertiesScan("com.baeldung.properties")
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
}
2.3@PropertySource
@Value和@ConfigurationProperties都可以用于获取配置文件的属性值,只是这两个注解在SpringBoot项目中都是获取默认配置文件的属性值,也就是application.yml和application.properties的属性值。
如果想引用其它配置文件的属性值,就可以使用@PropertySource注解。
新建一个user.properties的配置文件:
user.userName= root
user.isAdmin= true
user.regTime= 2019/11/01
user.isOnline= 1
user.maps.k1=v1
user.maps.k2=v2
user.lists=list1,list2
user.address.tel= 15899988899
user.address.name=上海
使用@PropertySource("classpath:user.properties")获取对应的properties文件,再用@ConfigurationProperties(prefix="user")进行属性映射:
package org.muses.jeeplatform.bean;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.PropertySource;
import org.springframework.stereotype.Component;
import java.util.Date;
import java.util.List;
import java.util.Map;
@Component
@PropertySource("classpath:user.properties")
@ConfigurationProperties(prefix = "user")
public class User {
private String userName;
private boolean isAdmin;
private Date regTime;
private Long isOnline;
private Map<String,Object> maps;
private List<Object> lists;
private Address address;
@Override
public String toString() {
return "User{" +
"userName='" + userName + '\'' +
", isAdmin=" + isAdmin +
", regTime=" + regTime +
", isOnline=" + isOnline +
", maps=" + maps +
", lists=" + lists +
", address=" + address +
'}';
}
public String getUserName() {
return userName;
}
public void setUserName(String userName) {
this.userName = userName;
}
public boolean isAdmin() {
return isAdmin;
}
public void setAdmin(boolean admin) {
isAdmin = admin;
}
public Date getRegTime() {
return regTime;
}
public void setRegTime(Date regTime) {
this.regTime = regTime;
}
public Long getIsOnline() {
return isOnline;
}
public void setIsOnline(Long isOnline) {
this.isOnline = isOnline;
}
public Map<String, Object> getMaps() {
return maps;
}
public void setMaps(Map<String, Object> maps) {
this.maps = maps;
}
public List<Object> getLists() {
return lists;
}
public void setLists(List<Object> lists) {
this.lists = lists;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
对应的Address类:
package org.muses.jeeplatform.bean;
/**
* <pre>
*
* </pre>
*
* @author nicky
* <pre>
* 修改记录
* 修改后版本: 修改人: 修改日期: 2019年11月03日 修改内容:
* </pre>
*/
public class Address {
private String tel;
private String name;
@Override
public String toString() {
return "Address{" +
"tel='" + tel + '\'' +
", name='" + name + '\'' +
'}';
}
public String getTel() {
return tel;
}
public void setTel(String tel) {
this.tel = tel;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
写一个Junit测试类:
package org.muses.jeeplatform;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.muses.jeeplatform.bean.User;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.junit4.SpringRunner;
@RunWith(SpringRunner.class)
@org.springframework.boot.test.context.SpringBootTest
public class SpringBootTest {
@Autowired
User user;
@Test
public void testConfigurationProperties(){
System.out.println(user);
}
}
读取成功,就不同将配置卸载默认的application.properties里了
User{userName='root', isAdmin=false, regTime=Fri Nov 01 00:00:00 CST 2019, isOnline=1, maps={k1=v1, k2=v2}, lists=[list1, list2], address=Address{tel='15899988899', name='上海市'}}
注意:对于@PropertySource注解,默认是不支持yml配置文件读取的,需要修改重写才可以。
2.4Mybatis相关注解
直接在Mapper类上面添加注解@Mapper,这种方式要求每一个mapper类都需要添加此注解,较麻烦。
通过使用@MapperScan可以指定要扫描的Mapper类的包的路径,比如:
@SpringBootApplication
@MapperScan("com.lz.water.monitor.mapper")
//添加对mapper包扫描
public class Application{
}
public static void main(String[] args){
SpringApplication.run(Application.class, args);
}
2.4.1Spring Boot整合mybatis
基础的MyBatis用法中,是通过SqlSessionFactoryBuilder来创建SqlSessionFactory的。而在MyBatis-Spring中,则使用SqlSessionFactoryBean来创建。
设置
要创建工厂bean,将下面的代码放到Spring的XML配置文件中:
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
</bean>
需要注意的是SqlSessionFactoryBean实现了Spring的FactoryBean接口(参看通过工厂 bean 自定义实例化逻辑)。这意味着Spring最终创建的bean并不是SqlSessionFactoryBean本身,而是工厂类(SqlSessionFactoryBean)的getObject()方法返回的结果。这种情况下,Spring将会在应用启动时为你创建SqlSessionFactory,并使用sqlSessionFactory这个名字存储起来。
使用FactoryBean自定义实例化逻辑
您可以为本身就是工厂的对象实现org.springframework.beans.factory.FactoryBean接口
FactoryBean接口是Spring IoC容器实例化逻辑的可插入点
如果您有复杂的初始化代码(用Java来表达比(可能)冗长的XML更好),那么您可以创建自己的FactoryBean,在类中编写复杂的初始化,然后将定制的FactoryBean插入到容器中。
FactoryBean接口提供三种方法:
Object getObjects():返回此工厂创建的对象的实例,实例可能被共享,这取决于返回的是单例还是原型。boolean isSingleton():如果FactoryBean返回单例,返回true;否则返回falseClass getObjectType():返回getObject()方法返回的对象类型,如果事先不知道该类型,则返回null。
FactoryBean的概念和接口在Spring框架的许多地方使用。Spring本身附带了50多个FactoryBean接口的实现。
当使用ApplicationContext的getBean()方法获取FactoryBean实例本身而不是它所产生的bean,则要使用&符号+id。比如,现有FactoryBean,它有id,在容器上调用getBean(“myBean”)将返回FactoryBean所产生的bean,调用getBean("&myBean")将返回FactoryBean它本身的实例。
等效的Java代码如下:
@Bean
public SqlSessionFactory sqlSessionFactory() {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(dataSource());
return factoryBean.getObject();
}
通常,在MyBatis-Spring中,你不需要直接使用SqlSessionFactoryBean或者对应的SqlSessionFactory。相反,session的工厂bean将会被注入到MapperFactoryBean或其它继承于SqlSessionDaoSupport的DAO(Data Access Object,数据访问对象)中。
/*
*整合mybatis SqlSessionFactoryBean
*/
@Bean
public SqlSessionFactoryBean mysqlCoreSqlSessionFactory(@Qualifier("mysqlCoreDataSource") DataSource mysqlCoreDataSource) throws IOException {
SqlSessionFactoryBean sessionFactory = new SqlSessionFactoryBean();
//数据源
sessionFactory.setDataSource(mysqlCoreDataSource);
//别名
sessionFactory.setTypeAliasesPackage(this.getAliasesPackage());
//mapper文件存储的位置
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
sessionFactory.setMapperLocations(resolver.getResources(this.getMapperFilePath()));
//开启驼峰标识 user_name --> userName
org.apache.ibatis.session.Configuration mybatisConf = new org.apache.ibatis.session.Configuration();
mybatisConf.setMapUnderscoreToCamelCase(true);
sessionFactory.setConfiguration(mybatisConf);
return sessionFactory;
}
属性
sqlSessionFactory有一个唯一的必要属性:用于JDBC的DataSource。这可以是任意的DataSource对象,它的配置方法和其它Spring数据库连接是一样的。
一个常用的属性是configLocation,它用来指定MyBatis的XML配置文件路径。它在需要修改MyBatis的基础配置非常有用。通常,基础配置指的是<settings>或者<typeAliases>元素。
需要注意的是,这个配置文件并不需要是一个完整的MyBatis配置,确切地说,任何环境配置(<environments>),数据源(<DataSource>)和MyBatis的事务管理器(<transactionManager>)都会被忽略。SqlSessionFactoryBean会创建它自有的MyBatis环境配置(Environment),并按要求设置自定义环境的值。
如果MyBatis在映射器类对于的路径下找不到与之对应的映射器XML文件,那么也需要配置文件。这时有两种解决办法:第一种是手动在MyBatis的XML配置文件中的<mappers>部分指定XML文件的类路径;第二种是设置工厂bean 的mapperLocations属性。
mapperLocations属性接受多个资源位置,这个属性可以用来指定MyBatis的映射器XML配置文件的位置。属性的值是一个Ant风格的字符串,可以指定加载一个目录中的所有文件,或者从一个目录开始递归搜索所有目录。比如
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource"/>
<property name="mapperLocations" value="classpath*:sample/config/mappers/**/*.xml"/>
</bean>
这会从类路径下加载所有在sample.config.mappers包和它的子包中的MyBatis映射器XML配置文件。
在容器管理事务的时候,您可能需要的一个属性是transactionFactoryClass。
自1.3.0版本开始,新增的configuration属性能够在没有对应的MyBatis XML配置文件的情况下,直接设置Configuration实例。
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean">
<property name="dataSource" ref="dataSource" />
<property name="configuration">
<bean class="org.apache.ibatis.session.Configuration">
<property name="mapUnderscoreToCamelCase" value="true"/>
</bean>
</property>
</bean>
2.4.2事务管理
2.4.2.1@EnbaleTransactionManagement
启用Spring的注解进行事务管理的功能,类似于Spring的支持<tx:*> XML命名空间。用于@Configuration类,以配置传统的、命令式事务管理或者反应性事务管理。
下面的示例演示使用PlatformTransactionManager进行命令式事务管理。对于反应性事务管理,配置一个Reactive TransactionManager替代。
@Configuration
@EnableTransactionManagement
public class AppConfig {
@Bean
public FooRepository fooRepository() {
// configure and return a class having @Transactional methods
return new JdbcFooRepository(dataSource());
}
@Bean
public DataSource dataSource() {
// configure and return the necessary JDBC DataSource
}
@Bean
public PlatformTransactionManager txManager() {
return new DataSourceTransactionManager(dataSource());
}
}
为了便于参考,可以将上面的示例与下面的Spring XML配置进行比较
<beans>
<tx:annotation-driven/>
<bean id="fooRepository" class="com.foo.JdbcFooRepository">
<constructor-arg ref="dataSource"/>
</bean>
<bean id="dataSource" class="com.vendor.VendorDataSource"/>
<bean id="transactionManager" class="org.sfwk...DataSourceTransactionManager">
<constructor-arg ref="dataSource"/>
</bean>
</beans>
在上述两个场景中,@EnableTransactionManagement和<tx:annotation-driven/>负责注册支持注释驱动的事务管理的必要Spring组件。例如,TransactionInterceptor和基于代理或者AspectJ的通知,当jdbcFooRepository's的@Transactional方法被调用时,这些通知将拦截器编织到调用堆栈中。
两个示例之间的一个小区别在于TransactionManagerbean的命名。在@Bean情况下,名称是txManager(根据方法的名称)。在XML中,名称是transactionManager。
2.5Spring加载资源文件
2.5.1资源查找器PathMatchingResourcePatternResolver
PathMatchingResourcePatternResolver是ResourcePatternResolver的常用实现类,下面从源码中看看spring是如何加载多个资源文件的。
构造器
/**
* Create a new PathMatchingResourcePatternResolver with a DefaultResourceLoader.
* <p>ClassLoader access will happen via the thread context class loader.
* @see org.springframework.core.io.DefaultResourceLoader
* 无参构造器,构造了一个DefaultResourceLoader实例作为ResourceLoader
*/
public PathMatchingResourcePatternResolver() {
this.resourceLoader = new DefaultResourceLoader();
}
/**
* Create a new PathMatchingResourcePatternResolver.
* <p>ClassLoader access will happen via the thread context class loader.
* @param resourceLoader the ResourceLoader to load root directories and
* actual resources with
* 传进来一个自定义的ResourceLoader
*/
public PathMatchingResourcePatternResolver(ResourceLoader resourceLoader) {
Assert.notNull(resourceLoader, "ResourceLoader must not be null");
this.resourceLoader = resourceLoader;
}
/**
* Create a new PathMatchingResourcePatternResolver with a DefaultResourceLoader.
* @param classLoader the ClassLoader to load classpath resources with,
* or {@code null} for using the thread context class loader
* at the time of actual resource access
* @see org.springframework.core.io.DefaultResourceLoader
* 构造了一个指定了ClassLoader的DefaultResourceLoader
*/
public PathMatchingResourcePatternResolver(@Nullable ClassLoader classLoader) {
this.resourceLoader = new DefaultResourceLoader(classLoader);
}
getResource方法
/**
* Return the ResourceLoader that this pattern resolver works with.
*/
public ResourceLoader getResourceLoader() {
return this.resourceLoader;
}
@Override
public Resource getResource(String location) {
//委托给了getResourceLoader()返回值获取Resource
//getResourceLoader()的返回值就是构造器产生的ResourceLoader
//所以呢,如果在实例化PathMatchingResourcePatternResolver是不知道ResourceLoader,那么使用的就是DefaultResourceLoader
return getResourceLoader().getResource(location);
}
getResources方法
@Override
public Resource[] getResources(String locationPattern) throws IOException {
Assert.notNull(locationPattern, "Location pattern must not be null");
//以classpath*:开头
if (locationPattern.startsWith(CLASSPATH_ALL_URL_PREFIX)) {
// a class path resource (multiple resources for same name possible)
//路径是否包含通配符 * 或者 ?ant风格
if (getPathMatcher().isPattern(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()))) {
// a class path resource pattern
return findPathMatchingResources(locationPattern);
}
else {
// all class path resources with the given name
// 路径不包含通配符 * 或 ?
// 返回classpath下的所有Resource
return findAllClassPathResources(locationPattern.substring(CLASSPATH_ALL_URL_PREFIX.length()));
}
}
else {
// Generally only look for a pattern after a prefix here,
// and on Tomcat only after the "*/" separator for its "war:" protocol.
// 计算路径前缀的长度,从后面截串,war:是针对tomcat解析用的 */是ant风格的路径模式
int prefixEnd = (locationPattern.startsWith("war:") ? locationPattern.indexOf("*/") + 1 :
locationPattern.indexOf(':') + 1);
// 路径是否包含通配符 * 或者 ?
if (getPathMatcher().isPattern(locationPattern.substring(prefixEnd))) {
// a file pattern
// 返回匹配的路径的Resource
return findPathMatchingResources(locationPattern);
}
else {
// a single resource with the given name
// 返回单个Resource
return new Resource[] {getResourceLoader().getResource(locationPattern)};
}
}
}
getResources方法的逻辑并不复杂,把资源查找分成了3类:
1、解析后路径中存在ant风格的资源路径,使用findPathMatchingResources查找资源
2、以classpath*:开头,且不存在ant风格的资源路径,使用findAllClassPathResource查找资源
3、其它路径使用getResource查找单个资源

726

被折叠的 条评论
为什么被折叠?



