spring的核心思想是 控制反转 和 切面编程
而其中控制反转的 实现是 依赖注入,控制反转是 一种通过描述 (在Java中可以是XML或者 注解 )并通过第三方去产生或获取特点对象的方式。第三方是 IOC容器
https://www.zhihu.com/question/23277575
spring IOC容器的设计是基于两个接口:
BeanFactory
ApplicationContext
一般使用这个,三个常用实现类
- ClassPathXmlApplicationContext 他可以加载类路径下的配置文件,要求诶之问价您必须在类路径下,不在的话,加载不了
- FileSystemXmlApplicationContext 它可以加载磁盘任意路径下的配置文件(必须有访问权限)
- AnnotationConfigApplicationContext 注解
ApplicationContext和BeanFactory另一个最大的不同之处在于:前者会利用Java反射机制自动识别出配置文件中定义的BeanPostProcessor,InstantitationAwareBeanPostProcessor和BeanFactoryPostProcessor,并自动将它们注册到应用上下文中,而后者需要在代码中通过手工调用addBeanPostProcessor方法进行注册。
这也是在实际在使用ApplicationContext的原则之一。
父子容器
通过HierarchicalBeanFactory
接口,spring的IOC容器可以建立父子层级体系,子容器能访问父容器,但父容器不能访问子容器
Bean的初始化分为三步:
- Resource定位
- BeanDefinition的载入
- BeanDefinition的注册
Bean的生命周期
装配Bean
bean之间的关系
继承 abstract, parent
依赖 depends-on
引用 ref
一个bean
依赖注入,为bean注入属性
<bean id="name" class="Object" >
//构造函数注入
<constructor-arg index="0" value="lin" />
//setter注入 <property name="age" value="12"/> <bean/>
第三种注入方式是 接口注入,可以注入外部资源
装配bean
通过XML文档装配bean,利用 ref 属性 引用 同一个文档的其他 bean。
通过XML文档,装配集合属性 <list> <map> <props> <set>
命名空间装配,c: 结构体属性声明赋值 ;p: 基本属性声明赋值 ; util: 创建集合 ,需要引用命名空间文档
通过注解的方式装配bean
组件扫描:@ComponentScan @Component
自动装配 :@Autowired (ByName - > ByType - > Constructor - > Method 3.0丢弃 )
自动装配的歧义性:@Qualifier(指定bean的id) @Primary
装载带有参数的构造类 使用的是@Autowired
在配置类上@Configuration,使用@Bean
注解自定义的bean初始化,消耗方法,
@Bean的属性 initMethod destroyMethod
装配的混合使用
@Import 导入配置类
@ImportResource 导入外部的XML文档
Java的装配注解
@Named(源于java依赖注入规范) = @Component
@Inject(源于java依赖注入规范) = @Autowired
bean的作用域 scope属性 @scope默认是单例模式
singleton prototype
request session globalSession
profile
@Profile 设置在配置类上,及@Configuration修饰的类上 ,或者注解在@Bean修饰的方法上
@ActiveProfiles 激活某种环境,dev ,prop ,test 等,修饰在启动类上
xml文档的标签也拥有profile 属性
JVM参数 设置profile ,JAVA_OPTS="-Dspring.profiles.active=test"
加载属性文件properties
@PropertySource(value={} ,ignoreResourceNotFound=true,encoding) 注入外部的资源文件
Environment类解析
PropertySourcesPlaceholderConfigurer类,作用是让spring能够解析属性占位符
@Value("${jdbc.datasource.driver}") 引用属性文件的值
使用xml方式加载属性文件
<context:property-placeholder /> 标签
多条件加载bean
@Conditional 条件化注入类,而这个类需要继承Condition接口,而Profile注解的底层就是用这个注解实现的。
@Conditional({myClass.class}) myClass.class 继承Condition接口 ,这个注解修饰在配置类的方法上,或者配置类
使用EL表达式
@Value("${}") 读取属性文件
@Value("#{}") 使用EL表达式,使用的是#
引用类的静态方法或常量 @Value("#{T(java.lang.Math).PI}")
概念:
连接点Joinpoint:一个类或者一段程序代码执行到具有分界性质的点
切点Pointcut:具体 就是某个类的 某个方法
增强Advice:在连接点处加入的一段代码片段
切面Apspect:切点和增强的组合
代理:一个类被AOP织入增强后,由原类和织入类混合成的代理类
引介:一种特殊的增强
织入:生成代理对象的过程,spring会根据切点方法是否有接口,使用那种代理方式,有接口使用JDK代理,没有接口使用CGLib代理
增强类型:before前置,after后置,around环绕;afterThrowing异常抛出,afterReturing返回通知
spring对AOP的支持,springAOP是一种基于方法拦截的AOP,换句话说,spring只能支持方法拦截的AOP
spring有4种方式去实现AOP的拦截功能。
使用ProxyFactoryBean和对于的接口实现AOP
使用XML文档配置AOP
使用@AspectJ注解驱动切面 常用
使用AspectJ注入切面
注解步骤
1 选择切点,选择某个类的某个方法
2 创建切面,对于动态代理概念而言,它就如同一个拦截器,使用@AspectJ注解一个类,就代表一个切面
3 连接点 ,5个通知类型,
@After("execution * com.org.src.Myclass.println(..)") public void after(){}
execution 代表执行方法的时候会触发,* 代表任意返回类型 类的全限定名,println拦截方法的名称,(..) 任意的参数
简化形式
@Pointcut("execution * com.org.src.Myclass.println(..))") public void print(){}
@Before("print()") public void before(){}
4 测试AOP
@EnableAspectJAutoProxy 修饰配置类,返回一个切面
<aop:aspectj-autoproxy
5 给通知传递参数
@After("execution * com.org.src.Myclass.println(..))" + "&&args(name)") public void after(String name){}
注意传递的参数一定是切点方法prinln的参数
6 引入@DeclareParents
spring和数据库编程
配置数据库资源的方式
- spring提供了一个简单的数据源类 SimpleDriverDataSource ,可以生成一个bean
- 使用第三方数据池,比如DBCP,使用dbcp.BasicDataSource
- 使用JNDI数据库连接池,如在Tomcat,Weblogic等Java EE服务器上配置了数据库,这时数据库存在一个JNDI名称,spring提供了一个类JndiObjectFatctoryBean 类
配置数据库源之后,就可以配置jdbcTemplate 模板
jdbcTemplate执行 普通的增删改查
执行多条SQL语句,jdbcTemplate.execute() 方法,它允许 传递 ConnectionCallBack , StatementCallBack 等接口进行回调,这些接口能获取 connection ,statement 对象。
spring-mybatis组合
配置SqlSessionFactory 的bean, 引用数据库
使用@Reposity注解所以的Mapper接口
配置MapperScannerConfigurer 的bean,属性basePackage=扫描mapper接口所在的层,另外的一个属性引用sqlsessionfactorybean。
spring数据库 事务管理
spring 使用 platformTransactionManager 接口 管理事务,创建事务,提交和 回滚。
mybatis使用的实现类是 DataSourceTransactionManager , 而 hibernate 使用的是 HibernateTransactionManager 类
XML配置数据库事务管理器,需要引入事务命名空间,创建bean,需要引用数据源。
Java代码方式,配置类 实现 TransactionManagerConfigurer 接口,实现 annotationDrivenTransactionManager 方法,这个方法返回的事务管理器。
同时配置类 需要 开启事务 @EnableTransactionManagement
以后再spring上下文中 使用 @Transactional ,spring就知道使用的事务管理器。
编程式事务
使用的是TransactionDefinition 接口,用的是DefaultTransactionDefinition 实现类,使用自定义的事务类,配合事务管理器有 使用者 控制事务的提交。
声明式事务
<tx :annotation -driven transaction-manager=" " />
@Transaction 常用的属性 isolation 隔离级别 propagation传播行为 timeout
spring定义的隔离级别有 5 种, 传播行为有 7种
spring的默认隔离级别是根据数据库的隔离级别变化的级别
传播行为常用的 有 默认REQUIRED 调用方法时,如果不存在当前事务,那么创建事务,如果之前已经存在事务了,那么就沿用之前的事务。
; REQUIRES_NEW 无论当前是否存在事务,方法都会在新的事务中运行
; NESTED 嵌套事务,如果方法抛出异常,只在自己的事务回滚,不会再主方法回滚。
@Transaction失效问题
因为transaction底层是AOP实现的,AOP的底层又是动态代理。
这就意味着 静态方法,类,或者 非public 方法,@Transaction是失效的。
如果public 方法内部调用了自身,@Transaction也是失效的。
springMVC
https://docs.spring.io/spring-framework/docs/current/spring-framework-reference/web.html
两个配置文件,一个是web.xml文件
<web-app>
<!--配置ContextLoaderListener初始化IOC容器 --> <listener> <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class> </listener> <!-- 配置spring IOC配置文件路径 --> <context-param> <param-name>contextConfigLocation</param-name> <param-value>/WEB-INF/app-context.xml</param-value> </context-param> <servlet> <servlet-name>app</servlet-name> <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class> <init-param> <param-name>contextConfigLocation</param-name> <param-value></param-value> </init-param> <load-on-startup>1</load-on-startup> </servlet> <servlet-mapping> <servlet-name>app</servlet-name> <url-pattern>/app/*</url-pattern> <!-- 拦截请求路径--> </servlet-mapping> </web-app>
第二步
与上面 web.xml 中的 <servlet-name>
元素配置的 app对应,这是 Spring MVC 的映射配置文件(xxx-servlet.xml),加载位置/WEB-INF/app-servlet.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" xmlns:p="http://www.springframework.org/schema/p" xmlns:context="http://www.springframework.org/schema/context" xsi:schemaLocation=" http://www.springframework.org/schema/beans https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd"> <context:component-scan base-package="org.example.web"/> <bean id="resolve" class="InternalResourceViewResolver p:prefix="WEB-INF/jsp" p:suffix=".jsp"/> <!-- ... --> </beans>
使用的注解
@Controller
@RequstMapping
@ResponseBody
@RequestParam
@SessionAttribute 从session中获取数据
@PathVariable 从URL获取参数
@RequestBody 接收JSON数据,以POJO形式; 接收JSON数组数据,转换成Java集合类型
重定向:redirect
重定向后,不能保存传递对象,MVC提供了一个flash属性,RedirectAttribute re,re.addFlashAttribute() 保存传递对象。原理,它会把数据保存在session中。
保存并获取属性参数
@RequestAttribute
@SessionAttribute 获取session数据
@SessionAttributes 标注类,保存数据到session中
@CookieValue
@RequestHeader
从cookie,header获取请求信息
3.0之后,使用Java代码的形式,代替web.xml文件
一个初始化类,实现WebApplicationInitializer接口
public class MyWebApplicationInitializer implements WebApplicationInitializer { @Override public void onStartup(ServletContext servletCxt) { // Load Spring web application configuration,加载配置类 AnnotationConfigWebApplicationContext ac = new AnnotationConfigWebApplicationContext(); ac.register(AppConfig.class); ac.refresh(); // Create and register the DispatcherServlet DispatcherServlet servlet = new DispatcherServlet(ac); ServletRegistration.Dynamic registration = servletCxt.addServlet("app", servlet); registration.setLoadOnStartup(1); registration.addMapping("/app/*"); } }
@EableWebMvc 注解修饰配置类,代表启动MVC的框架,相当于xx-servlet.xml文件
拦截器
自定义的拦截器 HandlerInterceptor接口,MVC提供了一个公共拦截器 HandlerInterceptorAdapter类
验证表单
spring 提供了对bean功能的校验,通过注解@Valid 表明那个bean 需要启动注解式的验证
JSR303注解
注解 | 功能 |
@Null /@NotNull | |
@AssertTrue /@AssertFalse | 注解的元素必须为true,false |
@Min @Max(value) | |
@DecimalMin @DecimalMax(value) | |
@Size(max,min) | 数的范围 |
@Digits(integer,fraction) | 一个数字,值在接受范围内 |
@Past @Future | |
@Pattern |
数据模型
Model数据模型接口
BindingAwareModelMap 类,派生出了 ExtendedModelMap类,此类又派生了ModelMap
视图View模型
ModelAndView
ViewResolver 接口
文件上传
MultipartResolver接口
实现类StandardServletMultipartResolver类,不依赖第三方包
表单属性form enctype="multipart/from-data"
MultipartFile接口, 也是一个文件,它是mvc提供的类
控制器上的接口可以是该类型,这个类型的接口数据有获取文件信息的方法,而保存数据的方法为transferTo
Part
Part 是servlet提供的类,用法和文件类似,也是接受文件对象。
文件下载
通过HttpServletResponse 设置 响应头信息,和获得输出流对象response.getOutputStream() 。
将文件或者图片信息 写入输出流。
数据转换和格式化
HttpMessageConverter Converter
格式化器 Formatter接口
@DateTimeFormat
@NumberFormat
为控制器添加通知
@ControllerAdvice 标注在类上,处理所有@RequestMapping方法的错误异常,属性basePackages={ 通知的控制类 }
@ExceptionHandler 某个异常类处理器,注册一个控制器异常
@InitBinder 是一个允许构建POJO参数的方法,允许构造控制器参数时,加入一定的自定义控制
@ModelAttribute 针对数据模型的注解,先于控制器运行,当标注方法返回对象时,保存到数据模型
处理异常的其他机制
默认情况下,spring将异常转换成合适的状态码,通过状态码确定异常发生的原因,找到对应的问题
异常隐射码类HttpStatus
@ResponseStatus(code=HttpStatus.XXX ,reason="NOT FOUND") public class RException extends RuntimeException{ }
使用
@ResponseStatus注解 为自定义的异常类加上映射码
在控制器controller中 增加 处理异常类的方法,方法前用上@ExceptionHandler
国际化
LocaleResolver接口 解析国际化
拥有4个实现类