一、spring是什么?
1、Spring是一个开源的轻量级的应用开发框架,其目的是用于简化企业级应用程序开发,降低开发者的开发难度。(简化开发:spring对常用的api,比如对JDBC做了封装,使用spring封装的jdbc访问数据库,就不用考虑获取连接、关闭连接等,极大的简化了代码)。
二、为什么要使用Spring
- 轻量级
轻量级是指从spring大小和开销而言spring都是轻量的,完整的spring框架可以在一个大小只有1M的jar文件里发布,并且spring所需的处理开销也是微不足道的。
- 控制反转
spring通过一种称作控制反转IOC的技术促进了低耦合。当应用了 IOC,一个对象依赖其他对象会通过被动的方式传递进来,而不是这个对象自己创建或者查找依赖对象。
- 面向切面
spring支持面向切面编程,并且把应用的业务逻辑和系统服务分开,如性能监测、事务管理、日志记录、加缓存等。
- 容器
spring包含并管理应用对象的配置和生命周期,在这个意义上它是一个容器,你可以配置你的每个bean如何被创建,基于一个可配置原型,你的bean可以创建一个单独的实例或者每次生成时都创建一个新的实例,以及他们是如何相互关联的。 - 框架集合
spring可以将简单的组件配置、组成为复杂的应用,在spring中应用对象被声明式地组合,典型的是在一个xml文件里。spring也提供了很多基础功能(事务管理、持久框架集成等)将应用逻辑的开发留给开发者。同时Spring为系统提供了一个整体的解决方案,开发者可以利用它本身提供的功能外,也可以与第三方框架和技术整合应用,可以自由选择采用哪种技术进行开发。(比如Spring整合SpringMVC、Spring整合MyBatis、Spring整合Struts2、Spring整合Hibernate、Spring整合Quartz[定时任务处理])。
总结:Spring的本质是管理软件中的对象,即创建对象和维护对象之间的关系。
三、spring的组成结构
1、Spring 核心组件图
解释说明:
组成 Spring 框架的每个模块(或组件)都可以单独存在,或者与其他一个或多个模块联合实现。每个模块的功能如下:
2、核心组件说明
(1)核心容器Spring Core 核心容器,提供Spring框架的基本功能。核心容器的主要组件是BeanFactory,它是工厂模式的实现。BeanFactory 使用控制反转(IOC)模式,将应用程序的配置和依赖性规范与实际的应用程序代码分开。
(2)Spring Context Spring上下文,是一个配置文件,向 Spring 框架提供上下文信息。Spring 上下文包括企业服务,例如 JNDI、EJB、电子邮件、国际化、校验和调度功能。
(3)Spring AOP 通过配置管理特性,Spring AOP 模块直接将面向切面的编程功能集成到了 Spring 框架中。可以很容易地使 Spring框架管理的任何对象支持AOP。Spring AOP模块为基于 Spring 的应用程序中的对象提供了事务管理服务。通过使用 Spring AOP,就可以将声明性事务管理集成到应用程序中。
(4)Spring DAO JDBC DAO 抽象层提供了有意义的异常层次结构,可用该结构来管理异常处理和不同数据库供应商抛出的错误消息。异常层次结构简化了错误处理,并且极大地降低了需要编写的异常代码数量(例如打开和关闭连接)。Spring DAO 的面向 JDBC 的异常遵从通用的 DAO 异常层次结构。
(5)Spring ORM Spring 框架插入了若干个 ORM 框架,从而提供了 ORM 的对象关系工具,其中包括JDO、Hibernate和iBatis SQL Map。所有这些都遵从 Spring 的通用事务和 DAO 异常层次结构。
(6) Spring Web Web上下文模块建立在应用程序上下文模块之上,为基于 Web 的应用程序提供了上下文。所以Spring 框架支持与 Jakarta Struts的集成。Web模块还简化了处理多部分请求以及将请求参数绑定到域对象的工作。
(7)Spring MVC框架 MVC 框架是一个全功能的构建 Web 应用程序的 MVC 实现。通过策略接口,MVC 框架变成为高度可配置的,MVC 容纳了大量视图技术,其中包括 JSP、Velocity、Tiles、iText 和 POI。
Spring 框架的功能可以用在任何J2EE服务器中,大多数功能也适用于不受管理的环境。Spring 的核心要点是:支持不绑定到特定J2EE服务的可重用业务和数据访问对象。毫无疑问,这样的对象可以在不同J2EE环境(Web或EJB)、独立应用程序、测试环境之间重用。
3、spring中的主要的Jar包
1).org.springframework.core 核心工具包,其他包依赖此包
2).org.springframework.beans 核心,包括:配置文件,创建和管理bean等
3).org.springframework.aop 面向切面编程,提供AOP的实现
4).org.springframework.context 提供IoC功能上的扩展服务,此外还提供许多企业级服务的支持,邮件、任务调度、JNDI定位、EJB集成、远程访问、缓存以及多种视图层框架的支持
5).org.springframework.web.mvc 包含SpringMVC应用开发时所需的核心类
6).org.springframework.transaction 为JDBC、Hibernate、JDO、JPA提供一致的声明式和编程式事务管理
7).org.springframework.web 包含Web应用开发时所需支持类
8).org.springframework.aspects 提供对AspectJ框架的支持
9).org.springframework.test 对junit等测试框架的简单封装
10).org.springframework.asm 3.0后提供自己独立的,反编译
11).org.springframework.context.support Context的扩展支持,用于mvc方面
12).org.springframework.expression Spring表达式语言
13).org.springframework.instument.tomcat spring对tomcat连接池的集成。
14).org.springframework.instument 对服务器的代理接口
15).org.springframework.jdbc 对jdbc的简单封装
16).org.springframework.jms 为简化jms api的使用而做的简单封装
17).org.springframework.orm 整合第三方orm,如hibernate/mybatis
18).16.org.springframework.oxm spring 对于object/xml映射的支持,可以让Java和xml来回切换。
org.springframework.web.portlet springMVC 的增强。
19).org.springframework.web.servlet 对Javaee6.0 servlet3.0的支持。
20).org.springframework.web.struts 整合对 struts 框架的支持,更方便容易的集成struts框架。
4、spring中的常用注解
bean 注入与装配的的方式有很多种,可以通过 xml,get set 方式,构造函数或者注解等。简单易用的方式就是使用 Spring 的注解了,Spring 提供了大量的注解方式。
(1)声明bean的注解
@Component 泛指组件,当标注的类没有明确分类是可以用该注解。
@Service 在业务逻辑层使用(service层)。
@Repository 在数据访问层使用(dao层)。
@Controller 在展现层使用,控制器的声明(C)。
@RestController 相当于@Controller和@ResponseBody的组合效果。
(2)注入bean的注解(依赖注入)
@Autowired Spring提供的工具(由Spring的依赖注入工具, 根据类型自动装配(byType
(BeanPostProcessor、BeanFactoryPostProcessor)自动注入。)
@Qualifier 根据名字的方式进行装配,不能单独使用 ,需要结合@Autowired来使用
参数就是要注入的bean的id
@Inject 由JSR-330提供
@Resource 由JSR-250提供, 先根据类型匹配, 没有再根据名字匹配, 都没有则抛出异常
(3) @Bean的属性支持
@Scope 设置Spring容器如何新建Bean实例(方法上,得有@Bean) 其设置类型包括:
Singleton (单例,一个Spring容器中只有一个bean实例,默认模式),
Protetype (每次调用新建一个bean),
Request (web项目中,给每个http request新建一个bean),
Session (web项目中,给每个http session新建一个bean),
GlobalSession(给每一个 global http session新建一个Bean实例)
@StepScope 在Spring Batch中还有涉及
@PostConstruct 由JSR-250提供,在构造函数执行完之后执行,等价于xml配置文件中bean的initMethod
@PreDestory 由JSR-250提供,在Bean销毁之前执行,等价于xml配置文件中bean的destroyMethod
@Lazy 延迟加载, 当第一次调用对象的时候创建, 参数有true和false, 默认为true
(4)java配置类相关注解
@Configuration 声明当前类为配置类,相当于xml形式的Spring配置(类上)
@Bean 注解在方法上,声明当前方法的返回值为一个bean,替代xml中的方式(方法上)
@Configuration 声明当前类为配置类,其中内部组合了@Component注解,表明这个类是一个bean(类上)
@ComponentScan 用于对Component进行扫描,相当于xml中的(类上)
@WishlyConfiguration 为@Configuration与@ComponentScan的组合注解,可以替代这两个注解
(5)切面(AOP)相关注解
@Aspect 声明一个切面(类上),使用@After、@Before、@Around定义建言(advice),
可直接将拦截规则(切点)作为参数。
@After 在方法执行之后执行(方法上)
@Before 在方法执行之前执行(方法上)
@Around 在方法执行之前与之后执行(方法上)
@PointCut 声明切点, 在java配置类中使用@EnableAspectJAutoProxy
注解开启Spring对AspectJ代理的支持(类上)
(6)@Value注解
@Value 为属性注入值(属性上) 支持如下方式的注入:
》注入普通字符
@Value("Michael Jackson")String name;
》注入操作系统属性
@Value("#{systemProperties['os.name']}")String osName;
》注入表达式结果
@Value("#{ T(java.lang.Math).random() * 100 }") String randomNumber;
》注入其它bean属性
@Value("#{domeClass.name}")String name;
》注入文件资源
@Value("classpath:com/hgs/hello/test.txt")String Resource file;
》注入网站资源
@Value("http://www.cznovel.com")Resource url;
》注入配置文件
Value("${book.name}")String bookName;
注入配置使用方法: ① 编写配置文件(test.properties)
book.name=《三体》
② @PropertySource 加载配置文件(类上)
@PropertySource("classpath:com/hgs/hello/test/test.propertie")
③ 还需配置一个PropertySourcesPlaceholderConfigurer的bean。
(7)环境切换
@Profile 通过设定Environment的ActiveProfiles来设定当前context需要使用的配置环境。(类或方法上)
@Conditional Spring4中可以使用此注解定义条件话的bean,通过实现Condition接口,并重写matches方法,从而决定该bean是否被实例化。(方法上)
(8)异步相关
@EnableAsync 配置类中,通过此注解开启对异步任务的支持,叙事性AsyncConfigurer接口(类上)
@Async 在实际执行的bean方法使用该注解来申明其是一个异步任务(方法上或类上所有的方法都将异步,需要@EnableAsync开启异步任务)
(9)定时任务相关
@EnableScheduling 在配置类上使用,开启计划任务的支持(类上)
@Scheduled 来申明这是一个任务,包括cron,fixDelay,fixRate等类型(方法上,需先开启计划任务的支持)
(10)@Enable*注解说明
这些注解主要用来开启对xxx的支持。 @EnableAspectJAutoProxy 开启对AspectJ自动代理的支持
@EnableAsync 开启异步方法的支持
@EnableScheduling 开启计划任务的支持
@EnableWebMvc 开启Web MVC的配置支持
@EnableConfigurationProperties 开启对@ConfigurationProperties注解配置Bean的支持
@EnableJpaRepositories 开启对SpringData JPA Repository的支持
@EnableTransactionManagement 开启注解式事务的支持
@EnableTransactionManagement 开启注解式事务的支持
@EnableCaching 开启注解式的缓存支持
(11)测试相关注解
@RunWith 运行器,Spring中通常用于对JUnit的支持
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration 用来加载配置ApplicationContext,其中classes属性用来加载配置类
@ContextConfiguration(classes={TestConfig.class})
(12)SpringMVC常用注解
@EnableWebMvc 在配置类中开启Web MVC的配置支持,如一些ViewResolver或者MessageConverter等,若无此句,重写WebMvcConfigurerAdapter方法(用于对SpringMVC的配置)。
@Controller 声明该类为SpringMVC中的Controller
@RequestMapping 用于映射Web请求,包括访问路径和参数(类或方法上)
@ResponseBody 支持将返回值放在response内,而不是一个页面,通常用户返回json数据(返回值旁或方法上)
@RequestBody 允许request的参数在request体中,而不是在直接连接在地址后面。(放在参数前)
@PathVariable 用于接收路径参数,比如@RequestMapping(“/hello/{name}”)申明的路径,将注解放在参数中前,即可获取该值,通常作为Restful的接口实现方法。
@RestController 该注解为一个组合注解,相当于@Controller和@ResponseBody的组合,注解在类上,意味着,该Controller的所有方法都默认加上了@ResponseBody。
@ControllerAdvice 通过该注解,我们可以将对于控制器的全局配置放置在同一个位置,注解了@Controller的类的方法可使用@ExceptionHandler、@InitBinder、@ModelAttribute注解到方法上, 这对所有注解了 @RequestMapping的控制器内的方法有效。
@ExceptionHandler 用于全局处理控制器里的异常
@InitBinder 用来设置WebDataBinder,WebDataBinder用来自动绑定前台请求参数到Model中。
@ModelAttribute 本来的作用是绑定键值对到Model里,在@ControllerAdvice中是让全局的@RequestMapping 都能获得在此处设置的键值对。
@RequestHeader注解方便我们获取请求头信息
附:Lombok插件常用注解
@Data注解:在JavaBean或类JavaBean中使用,这个注解包含范围最广,它包含getter、setter、NoArgsConstructor注解,即当使用当前注解时,会自动生成包含的所有方法;
@getter注解:在JavaBean或类JavaBean中使用,使用此注解会生成对应的getter方法;
@setter注解:在JavaBean或类JavaBean中使用,使用此注解会生成对应的setter方法;
@NoArgsConstructor注解:在JavaBean或类JavaBean中使用,使用此注解会生成对应的无参构造方法;
@AllArgsConstructor注解:在JavaBean或类JavaBean中使用,使用此注解会生成对应的有参构造方法;
@ToString注解:在JavaBean或类JavaBean中使用,使用此注解会自动重写对应的toStirng方法;
@EqualsAndHashCode注解:在JavaBean或类JavaBean中使用,使用此注解会自动重写对应的equals方法和hashCode方法;
@Slf4j:在需要打印日志的类中使用,当项目中使用了slf4j打印日志框架时使用该注解,会简化日志的打印流程,只需调用info方法即可;
@Log4j:在需要打印日志的类中使用,当项目中使用了log4j打印日志框架时使用该注解,会简化日志的打印流程,只需调用info方法即可;
在使用以上注解需要处理参数时,处理方法如下(以@ToString注解为例,其他注解同@ToString注解)
@ToString(exclude="column")
意义:排除column列所对应的元素,即在生成toString方法时不包含column参数;
@ToString(exclude={"column1","column2"})
意义:排除多个column列所对应的元素,其中间用英文状态下的逗号进行分割,即在生成toString方法时不包含多个column参数;
@ToString(of="column")
意义:只生成包含column列所对应的元素的参数的toString方法,即在生成toString方法时只包含column参数;;
@ToString(of={"column1","column2"})
意义:只生成包含多个column列所对应的元素的参数的toString方法,其中间用英文状态下的逗号进行分割,即在生成toString方法时只包含多个column参数;
@Accessors(chain=true)
链式加载
四、Spring 与第三方的结合
五、Spring IOC控制反转
1、IOC(Inversion of Control),控制反转
所谓的控制反转,就是指将对象的创建,对象的存储(map),对象的管理(依赖查找,依赖注入)交给了spring容器(spring容器是spring中的一个核心模块,用于管理对象)。Spring 通过一个配置文件描述 Bean 及 Bean 之间的依赖关系,利用 Java 语言的反射功能实例化Bean 并建立 Bean 之间的依赖关系。 Spring 的 IoC 容器在完成这些底层工作的基础上,还提供了 Bean 实例缓存、生命周期管理、 Bean 实例代理、事件发布、资源装载等高级服务。
- 传统方式创建对象:在此之前,当需要对象时,通常是利用new关键字创建一个对象。
//1.创建一个Hello对象
Hello hello = new Hello();
//2.调用hello对象的方法
hello.sayHi();
缺点:但由于new对象,会提高代码之间耦合性。
所谓的耦合是软件结构内模块之间联系程度用耦合来度量,耦合强弱取决于模块相互之间接口的复杂程度,一般由模块之间的调用方式、传递信息的类型和数量来决定。
- 把对象的创建交给spring容器管理
//1.从spring容器中获取bean对象(而不是自己new)
Hello hello = (Hello) ac.getBean("hello");
//2.调用hello对象的方法
hello.sayHi();
优点:只需要将类提前配置在spring配置文件中,就可以将对象的创建交给spring容器,当需要对象时,不需要自己创建,而是直接通过spring获取即可,省去了new对象,可以降低代码之间的耦合性。
2、Spring创建对象的过程
图示
说明:Spring 启动时读取应用程序提供的 Bean 配置信息,并在 Spring 容器中生成一份相应的 Bean 配置注册表,然后根据这张注册表实例化 Bean,装配好 Bean 之间的依赖关系,为上层应用提供备就绪的运行环境。其中 Bean 缓存池为 HashMap 实现。
3、IOC(控制反转) 容器初始化过程分析
说明:1、通过AnnotationConfigApplicationContext类读取被@componentScan注解标记的配置类(本包,或者子包),获取配置类的信息,通过配置类信息找到被spring注解标识的类,然后系统底层对这些信息进行解析,解析后将每个bean的配置信息存储在Map集合中,通过反射机制根据类的配置信息,创建实例对象,然后把每个实例对象存储在map集合中,并通过map集合给定对象的作用域范围,然后通过依赖注入维护对象之间的关系,通过getBean方法获取bean对象。作用域为singlenton会放在bean池中,对象是容器初始化的时候创建的。
如果设置lazy则延迟加载。
拓展:
拓展Spring IOC控制反转原理
一、概念:
Spring 通过一个配置文件描述 Bean 及 Bean 之间的依赖关系,利用 Java 语言的反射功能实例化Bean 并建立 Bean 之间的依赖关系。 Spring 的 IoC 容器在完成这些底层工作的基础上,还提供了 Bean 实例缓存、生命周期管理、 Bean 实例代理、事件发布、资源装载等高级服务。
二、Spring容器的高层视图:
Spring 启动时读取应用程序提供的 Bean 配置信息,并在 Spring 容器中生成一份相应的 Bean 配置注册表,然后根据这张注册表实例化 Bean,装配好 Bean 之间的依赖关系,为上层应用提供准备就绪的运行环境。其中 Bean 缓存池为 HashMap 实现。
三、springIOC 容器实现
BeanFactory-框架基础设施
BeanFactory 是 Spring 框架的基础设施,面向 Spring 本身;ApplicationContext 面向使用Spring 框架的开发者,几乎所有的应用场合我们都直接使用 ApplicationContext 而非底层的 BeanFactory。
1、 BeanDefinitionRegistry 注册表
Spring 配置文件中每一个节点元素在 Spring 容器里都通过一个 BeanDefinition 对象表示,它描述了 Bean 的配置信息。而 BeanDefinitionRegistry 接口提供了向容器手工注册BeanDefinition 对象的方法。
2、 BeanFactory 顶层接口
位于类结构树的顶端 ,它最主要的方法就是 getBean(String beanName),该方法从容器中返回特定名称的 Bean,BeanFactory 的功能通过其他的接口得到不断扩展。
3、 ListableBeanFactory
该接口定义了访问容器中 Bean 基本信息的若干方法,如查看 Bean 的个数、获取某一类型Bean 的配置名、查看容器中是否包括某一 Bean 等方法。
4、HierarchicalBeanFactory 父子级联
父子级联 IoC 容器的接口,子容器可以通过接口方法访问父容器; 通过
HierarchicalBeanFactory 接口, Spring 的 IoC 容器可以建立父子层级关联的容器体系,子容器可以访问父容器中的 Bean,但父容器不能访问子容器的 Bean。Spring 使用父子容器实现了很多功能,比如在 Spring MVC 中,展现层 Bean 位于一个子容器中,而业务层和持久层的 Bean 位于父容器中。这样,展现层 Bean 就可以引用业务层和持久层的 Bean,而业务层和持久层的 Bean 则看不到展现层的 Bean。
5、ConfigurableBeanFactory
是一个重要的接口,增强了 IoC 容器的可定制性,它定义了设置类装载器、属性编辑器、容器初始化后置处理器等方法。
6、AutowireCapableBeanFactory 自动装配
定义了将容器中的 Bean 按某种规则(如按名字匹配、按类型匹配等)进行自动装配的方法。
7、ingletonBeanRegistry 运行期间注册单例 Bean
定义了允许在运行期间向容器注册单实例 Bean 的方法;对于单实例( singleton)的 Bean来说,BeanFactory 会缓存 Bean 实例,所以第二次使用 getBean() 获取 Bean 时将直接从IoC 容器的缓存中获取 Bean 实例。Spring 在 DefaultSingletonBeanRegistry 类中提供了一个用于缓存单实例 Bean 的缓存器,它是一个用 HashMap 实现的缓存器,单实例的 Bean 以beanName 为键保存在这个 HashMap 中。
8、依赖日志框框
在初始化 BeanFactory 时,必须为其提供一种日志框架,比如使用 Log4J, 即在类路径下提供 Log4J 配置文件,这样启动 Spring 容器才不会报错。
ApplicationContext 面向开发应用
ApplicationContext 由 BeanFactory 派生而来,提供了更多面向实际应用的功能ApplicationContext 继承了 HierarchicalBeanFactory 和 ListableBeanFactory 接口,在此基础上,还通过多个其他的接口扩展了 BeanFactory 的功能。
1、ClassPathXmlApplicationContext:默认从类路径加载配置文件。
2、FileSystemXmlApplicationContext:默认从文件系统中装载配置文件。
3、ApplicationEventPublisher:让容器拥有发布应用上下文事件的功能,包括容器启动事件、关闭事件等。
4、MessageSource:为应用提供 i18n 国际化消息访问的功能。
5.、ResourcePatternResolver :所 有 ApplicationContext 实现类都实现了类似于PathMatchingResourcePatternResolver 的功能,可以通过带前缀的 Ant 风格的资源文件路径装载 Spring 的配置文件。
6、 LifeCycle:该接口是 Spring 2.0 加入的,该接口提供了 start()和 stop()两个方法,主要用于控制异步处理过程。在具体使用时,该接口同时被 ApplicationContext 实现及具体Bean 实现, ApplicationContext 会将 start/stop 的信息传递给容器中所有实现了该接口的 Bean,以达到管理和控制 JMX、任务调度等目的。
7、ConfigurableApplicationContext 扩展于 ApplicationContext,它新增加了两个主要的方法: refresh()和 close(),让 ApplicationContext 具有启动、刷新和关闭应用上下文的能力。在应用上下文关闭的情况下调用 refresh()即可启动应用上下文,在已经启动的状态下,调用 refresh()则清除缓存并重新装载配置信息,而调用 close()则可关闭应用上下文。
WebApplication 体系架构
WebApplicationContext 是专门为 Web 应用准备的,它允许从相对于 Web 根目录的路径中装载配置文件完成初始化工作。从 WebApplicationContext 中可以获得ServletContext 的引用,整个 Web 应用上下文对象将作为属性放置到 ServletContext中,以便 Web 应用环境可以访问 Spring 应用上下文。
Spring Bean 作用域
Spring 3 中为 Bean 定义了 5 中作用域,分别为 singleton(单例)、prototype(原型)、request、session 和 global session,5 种作用域说明如下:
singleton:单例模式(多线程下不安全)
- singleton:单例模式(多线程下不安全),Spring IoC 容器中只会存在一个共享的 Bean 实例,无论有多少个Bean 引用它,始终指向同一对象。该模式在多线程下是不安全的。Singleton 作用域是Spring 中的缺省作用域,也可以显示的将 Bean 定义为 singleton 模式,配置为:
prototype:原型模式每次使用时创建 - prototype:原型模式,每次通过 Spring 容器获取 prototype 定义的 bean 时,容器都将创建一个新的 Bean 实例,每个 Bean 实例都有自己的属性和状态,而 singleton 全局只有一个对象。根据经验,对有状态的bean使用prototype作用域,而对无状态的bean使用singleton作用域。
Request:一次 request 一个实例 - request:在一次 Http 请求中,容器会返回该 Bean 的同一实例。而对不同的 Http 请求则会产生新的 Bean,而且该 bean 仅在当前 Http Request 内有效,当前 Http 请求结束,该 bean实例也将会被销毁。
session - session:在一次 Http Session 中,容器会返回该 Bean 的同一实例。而对不同的 Session 请求则会创建新的实例,该 bean 实例仅在当前 Session 内有效。同 Http 请求相同,每一次session 请求创建新的实例,而不同的实例之间不共享属性,且实例仅在自己的 session 请求内有效,请求结束,则实例将被销毁。
global Session - global Session:在一个全局的 Http Session 中,容器会返回该 Bean 的同一个实例,仅在使用 portlet context 时有效。
Spring Bean 生命周期
实例化 - 实例化一个 Bean,也就是我们常说的 new。
IOC 依赖注入 - 按照 Spring 上下文对实例化的 Bean 进行配置,也就是 IOC 注入。
setBeanName 实现。 - 如果这个 Bean 已经实现了 BeanNameAware 接口,会调用它实现的 setBeanName(String)方法,此处传递的就是 Spring 配置文件中 Bean 的 id 值
BeanFactoryAware 实现。 - 如果这个 Bean 已经实现了 BeanFactoryAware 接口,会调用它实现的 setBeanFactory,setBeanFactory(BeanFactory)传递的是 Spring 工厂自身(可以用这个方式来获取其它 Bean,只需在 Spring 配置文件中配置一个普通的 Bean 就可以)。
ApplicationContextAware 实现 - 如果这个 Bean 已经实现了 ApplicationContextAware 接口,会调用
setApplicationContext(ApplicationContext)方法,传入 Spring 上下文(同样这个方式也可以实现步骤 4 的内容,但比 4 更好,因为 ApplicationContext 是 BeanFactory 的子接口,有更多的实现方法)
postProcessBeforeInitialization 接口实现-初始化预处理 - 如果这个 Bean 关联了 BeanPostProcessor 接口,将会调用postProcessBeforeInitialization(Object obj, String s)方法,BeanPostProcessor 经常被用作是 Bean 内容的更改,并且由于这个是在 Bean 初始化结束时调用那个的方法,也可以被应用于内存或缓存技术。
init-method - 如果 Bean 在 Spring 配置文件中配置了 init-method 属性会自动调用其配置的初始化方法。
postProcessAfterInitialization - 如果这个 Bean 关联了 BeanPostProcessor 接口,将会调用
postProcessAfterInitialization(Object obj, String s)方法。注:以上工作完成以后就可以应用这个 Bean 了,那这个 Bean 是一个 Singleton 的,所以一般情况下我们调用同一个 id 的 Bean 会是在内容地址相同的实例,当然在 Spring 配置文件中也可以配置非 Singleton。
Destroy 过期自动清理阶段 - 当 Bean 不再需要时,会经过清理阶段,如果 Bean 实现了 DisposableBean 这个接口,会调用那个其实现的 destroy()方法;
destroy-method 自配置清理 - 最后,如果这个 Bean 的 Spring 配置中配置了 destroy-method 属性,会自动调用其配置的销毁方法。
- bean 标签有两个重要的属性(init-method 和 destroy-method)。用它们你可以自己定制初始化和注销方法。它们也有相应的注解(@PostConstruct 和@PreDestroy)。
10、Spring DI依赖注入
DI依赖注入,即组件之间的依赖关系由容器在应用系统运行期来决定,也就是由容器动态地将某种依赖关系的目标对象实例注入到应用系统中的各个关联的组件之中。
简单来说,所谓的依赖注入其实就是,在创建对象的同时或之后,如何给对象的属性赋值。
11、Spring 依赖注入四种方式
5 种不同方式的自动装配
Spring 装配包括手动装配和自动装配,手动装配是有基于 xml 装配、构造方法、setter 方法等自动装配有五种自动装配的方式,可以用来指导 Spring 容器用自动装配方式来进行依赖注入。
1、构造器注入
/带参数,方便利用构造器进行注入/
public CatDaoImpl(String message){
this. message = message;
}
2、setter 方法注入
public class Id {
private int id;
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
}
3、静态工厂注入
静态工厂顾名思义,就是通过调用静态工厂的方法来获取自己需要的对象,为了让 spring 管理所有对象,我们不能直接通过"工程类.静态方法()"来获取对象,而是依然通过 spring 注入的形式获取:
public class DaoFactory { //静态工厂
public static final FactoryDao getStaticFactoryDaoImpl(){
return new StaticFacotryDaoImpl();
}
}
public class SpringAction {
private FactoryDao staticFactoryDao; //注入对象
//注入对象的 set 方法
public void setStaticFactoryDao(FactoryDao staticFactoryDao) {
this.staticFactoryDao = staticFactoryDao;
}
}
//factory-method="getStaticFactoryDaoImpl"指定调用哪个工厂方法
4、实例工厂
实例工厂的意思是获取对象实例的方法不是静态的,所以你需要首先 new 工厂类,再调用普通的实例方法:
public class DaoFactory { //实例工厂
public FactoryDao getFactoryDaoImpl(){
return new FactoryDaoImpl();
}
}
public class SpringAction {
private FactoryDao factoryDao; //注入对象
public void setFactoryDao(FactoryDao factoryDao) {
this.factoryDao = factoryDao;
}
}
- no:默认的方式是不进行自动装配,通过显式设置 ref 属性来进行装配。
- byName:通过参数名 自动装配,Spring 容器在配置文件中发现 bean 的 autowire 属性被设置成 byname,之后容器试图匹配、装配和该 bean 的属性具有相同名字的 bean。
- byType:通过参数类型自动装配,Spring 容器在配置文件中发现 bean 的 autowire 属性被设置成 byType,之后容器试图匹配、装配和该 bean 的属性具有相同类型的 bean。如果有多个 bean 符合条件,则抛出错误。
- constructor:这个方式类似于 byType, 但是要提供给构造器参数,如果没有确定的带参数的构造器参数类型,将会抛出异常。
- autodetect:首先尝试使用 constructor 来自动装配,如果无法工作,则使用 byType 方式。
12、Spring框架用到的9个设计模式
1、工厂设计模式(简单工厂和工厂方法)
Spring使用工厂模式可以通过BeanFactory或ApplicationContext创建bean对象。
2、单例模式
Spring中bean的默认作用域就是singleton。
3、适配器模式
在Spring MVC中,DispatcherServlet根据请求信息调用HandlerMapping,解析请求对应的Handler,解析到对应的Handler(也就是我们常说的Controller控制器)后,开始由HandlerAdapter适配器处理。
4、装饰着设计模式
Spring 中配置DataSource的时候,DataSource可能是不同的数据库和数据源。我们能否根据客户的需求在少修改原有类的代码下切换不同的数据源?这个时候据需要用到装饰者模式。
5、代理(proxy)模式
Spring AOP就是基于动态代理的,如果要代理的对象,实现了某个接口,那么Spring AOP会使用JDK Proxy,去创建代理对象,而对于没有实现接口的对象,就无法使用JDK Proxy去进行代理了,这时候Spring AOP会使用Cglib,这时候Spring AOP会使用Cglib生成一个被代理对象的子类来作为代理
6、观察者模式
Spring事件驱动模型就是观察者模式很经典的应用。
7、策略模式
Spring 框架的资源访问接口就是基于策略设计模式实现的。
8、模板方法模式
Spring中jdbcTemplate、hibernateTemplate等以Template结尾的对数据库操作的类,它们就使用到模板模式
13、谈谈你对SpringAOP的理解?
AOP 是软件设计领域中的面向切面编程,它是面向对象编程(OOP)的一种补充和完善实际项目中我们通常将面向对象理解为一个静态过程(例如一个系统有多少个模块,一个模块有哪些对象,对象有哪些属性),面向切面中包含一个一个动态过程(在对象运行时动态织入一些功能。)
简单来说:AOP就是要在基于OCP(开闭原则)在不改变原有系统核心业务代码的基础上动态添加一些扩展功能并可以"控制"对象的执行。
14、AOP的主要应用场景? - Authentication 权限
- Caching 缓存
- Context passing 内容传递
- Error handling 错误处理
- Lazy loading 懒加载
- Debugging 调试
- logging, tracing, profiling and monitoring 记录跟踪 优化 校准
- Performance optimization 性能优化
- Persistence 持久化
- Resource pooling 资源池
- Synchronization 同步
- Transactions 事务
15、AOP底层原理实现分析?
AOP底层基于代理机制实现功能扩展。
1、假如目标对象(被代理对象)实现接口,则底层可以采用JDK动态代理机制为目标对象创建代理对象(目标类和代理类会实现共同接口)
2、假如目标对象(被代理对象)没有实现接口,则底层可以采用CGLIB代理机制为目标对象创建代理对象(默认创建的代理类会继承目标对象类型)。
说明:
Spring boot2.x 中AOP现在默认使用的CGLIB代理,假如需要使用JDK动态代理可以在配置文件(applicatiion.properties)中进行如下配置:
spring.aop.proxy-target-class=false
16、AOP应用原理分析?
基于CGLIB代理实现Spring AOP:(目标是通过继承实现功能扩展)
基于JDK动态代理实现Spring AOP:(通过组合实现功能扩展)
17、AOP核心概念?
1、切面(aspect):类是对物体特征的抽象,切面就是对横切关注点的抽象。
2、横切关注点:对哪些方法进行拦截,拦截后怎么处理,这些关注点称之为横切关注点。
3、连接点(joinpoint):被拦截到的点,因为 Spring 只支持方法类型的连接点,所以在 Spring。
中连接点指的就是被拦截到的方法,实际上连接点还可以是字段或者构造器。
4、切入点(pointcut):对连接点进行拦截的定义。
5、通知(advice):所谓通知指的就是指拦截到连接点之后要执行的代码,通知分为前置、后置、异常、最终、环绕通知五类。
6、目标对象:代理的目标对象
7、织入(weave):将切面应用到目标对象并导致代理对象创建的过程
8、引入(introduction):在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。
18、切面通知应用增强分析
在AOP编程中有五种类型的通知:
1、前置通知 (@Before) 方法执行之前执行
2、返回通知 (@AfterReturning) 方法return之后执行
3、异常通知 (@AfterThrowing) 方法出现异常之后执行
4、后置通知 (@After) : 又称之为最终通知(finally)
5、环绕通知 (@Around) :重点掌握
19、切入点表达式增强
Spring中通过切入点表达式定义具体切入点,其常用AOP切入点表达式定义及说明:
指示符 作用
bean 用于匹配指定bean id的的方法执行
within 用于匹配指定包名下类型内的方法执行
execution 用于进行细粒度方法匹配执行具体业务
@annotation 用于匹配指定注解修饰的方法执行
1、Bean表达式应用增强
bean表达式应用于类级别,实现粗粒度的切入点定义
bean(“userServiceImpl”)) 指定一个类中所有方法
bean("*ServiceImpl") 指定所有的后缀为serviceImpl的类
说明:bean表达式内部的对象是由spring容器管理的一个bean对象,表达式内部的内部的名字应该时spring容器中某个bean的key.
2、Within表达式应用增强
within表达式应用于类级别,实现粗粒度的切入点表达式定义:
within(“aop.service.UserServiceImpl”) 指定类,只能指定一个类
within(“aop.service.") 只包括当前目录下的类
within("aop.service…”) 指定当前目录包含所有子目录中的类
3、Execution表达式应用增强
execution表达式应用于方法级别,细粒度的切入点表达式定义
语法:execution(返回值类型 包名.类名.方法名(参数列表))
execution(void aop.service.UserServiceImpl.addUser()) 匹配方法
execution(void aop.service.PersonServiceImpl.addUser(String)) 方法参数必须为字符串
execution(* aop.service….(…)) 万能配置
4、@annotation表达式应用增强
@annotaion表达式应用于方法级别,实现细粒度的切入点表达式定义:
@annotation(com.jt.common.anno.RequestLog) 指定一个需要实现增强功能的方法
其中:RequestLog为我们自己定义的注解,当我们使用@RequestLog注解修饰业务层方法时,系统底层会在执行此方法时进行扩展操作.
20. Spring 事务处理
事务(Transaction)是一个业务,是一个不可分割的逻辑工作单元,具备ACID特性,实际工作中可借助Spring进行事务管理。
1、事务四大特性:ACID:
- 原子性(一个事务中的多个操作要么都成功要么都失败)
- 一致性(例如存钱操作,存之前和存之后的总钱数应该是一致的)
- 隔离性(事务与事务应该是相互隔离的)
- 持久性(事务一旦提交,数据要持久保存)
2、事务的隔离级别:
DEFAULT这是一个PlatfromTransactionManager默认的隔离级别,使用数据库默认的事务隔离级别
未提交读(read uncommited):脏读,不可重复读,虚读都有可能发生
已提交读(read commited):避免脏读。但是不可重复读和虚读都有可能发生;
可重复读(repeatable read):避免脏读和不可重复读,但是虚读有可能发生;
串行化的(serializable):避免以上所有读问题。
MySQL默认:可重复读
Oracle默认:已提交读
3、事务传播行为种类
Spring在TransactionDefinition接口中规定了7种类型的事务传播行为,它们规定了事务方法和事务方法发生嵌套调用时事务如何进行传播:
下表为事务传播行为类型
Spring提供了两种事务管理方式, 编程式事务和声明式事务。编程式事务指的是通过编码方式实现事务;声明式事务基于 AOP,将具体业务逻辑与事务处理解耦。声明式事务管理使业务代码逻辑不受污染, 因此在实际使用中声明式事务用的比较多。
Spring中声明式事务处理有两种方式,一种是在配置文件(xml)中做相关的事务规则声明,另一种是基于@Transactional 注解的方式。
本讲重点讲解实际项目中最常用的声明式事务管理,以简化事务的编码操作。
21、Spring 事务中的基本实现
在SpringBoot进行资源整合和配置时,需要类或方法上使用@Transactional注解告诉spring框架我们要在此类的方法执行时添加事务控制。
1、timeout 事务的超时时间,默认值为-1,表示没有超时显示。如果配置了具体时间,则超过该时间限制但事务还没有完成,则自动回滚事务。
2、read-only 指定事务是否为只读事务,默认值为 false;为了忽略那些不需要事务的方法,比如读取数据,可以设置 read-only 为 true。
3、rollback-for 用于指定能够触发事务回滚的异常类型,如果有多个异常类型需要指定,各类型之间可以通过逗号分隔。
4、no-rollback- for 抛出 no-rollback-for 指定的异常类型,不回滚事务。
5、isolation 事务的隔离度,默认值采用 DEFAULT。
说明:@Transactional 注解可以用在方法上也可以添加到类级别上。当把@Transactional 注解放在类级别时,表示所有该类的公共方法都配置相同的事务属性信息。当类级别配置了@Transactional,方法级别也配置了@Transactional,应用程序会以方法级别的事务属性信息来管理事务,换言之,方法级别的事务属性信息会覆盖类级别的相关配置信息。
22、事务传播特性增强分析
事务传播(Propagation)特性指不同业务(service)对象中的事务方法之间相互调用时,事务的传播方式.
重点掌握 Propagation.REQUIRED (最常用,默认)
2nal(propagation=Propagation.REQUIRED) 如果没有事务创建新事务, 如果当前有事务参与当前事务中。
@Transactional(propagation=Propagation.REQUIRES_NEW)
必须是新事务, 如果有当前事务, 挂起当前事务并且开启新事务.
23、常见的FAQ
- 什么是OCP原则(开闭原则):允许扩展,不允许修改
- 什么是DIP原则 (依赖倒置):依赖于抽象而非具体
- 什么是单一职责原则(一个类或接口的职责不要太多)
- Spring 中AOP的有哪些配置方式(xml和注解)
- Spring 中AOP 的通知有哪些基本类型
- Spring 中AOP是如何为Bean对象创建代理对象的?
- Spring 中AOP切面的执行顺序如何指定?@Order
- Spring 单体架构项目中事务的控制要通过Connection对象实现,
Connection对象能多线程共享吗?不可以. - Spring 如何保证一个线程一个Connection对象?借助ThreadLocal实现.
24、在 Spring 中如何注入一个 java 集合?
Spring 提供以下几种集合的配置元素:
类型用于注入一列值,允许有相同的值。
类型用于注入一组值,不允许有相同的值。
类型用于注入一组键值对,键和值都可以为任意类型。
类型用于注入一组键值对,键和值都只能为 String 类型。 - 什么是 Spring 的内部 bean?
当一个 bean 仅被用作另一个 bean 的属性时,它能被声明为一个内部 bean,为了定义 inner bean,在Spring 的 基于 XML 的 配置元数据中,可以在 或 元素内使用 元素,内
部 bean 通常是匿名的,它们的 Scope 一般是 prototype。