- VisualStudio2022插件的安装及使用-编程手把手系列文章
- pprof-在现网场景怎么用
- C#实现的下拉多选框,下拉多选树,多级节点
- 【学习笔记】基础数据结构:猫树
Spring 是一款开源的轻量级 Java 开发框架,旨在提高开发人员的开发效率以及系统的可维护性.
Spring的一个最大的目的就是使JAVA EE开发更加容易。同时,Spring之所以与Struts、Hibernate等单层框架不同,是因为Spring致力于提供一个以统一的、高效的方式构造整个应用,并且可以将单层框架以最佳的组合揉和在一起建立一个连贯的体系。可以说Spring是一个提供了更完善开发环境的一个框架,可以为POJO(Plain Ordinary Java Object)对象提供企业级的服务.
从Spring 框架的特性来看:
从使用Spring 框架的优势看:
Spring5.x 版本中 Web 模块的 Portlet 组件已经被废弃掉,同时增加了用于异步响应式处理的 WebFlux 组件.
从最下层往上介绍 。
Spring 团队提倡测试驱动开发(TDD)。有了控制反转 (IoC)的帮助,单元测试和集成测试变得更简单.
Spring 的测试模块对 JUnit(单元测试框架)、TestNG(类似 JUnit)、Mockito(主要用来 Mock 对象)、PowerMock(解决 Mockito 的问题比如无法模拟 final, static, private 方法)等等常用的测试框架支持的都比较好。而且还额外提供了一些基于 Spring 的测试功能,比如在测试 Web 框架时,模拟 Http 请求的功能.
包含Mock Objects, TestContext Framework, Spring MVC Test, WebTestClient.
源码对应模块如下:
Spring 框架的核心模块,也可以说是基础模块,主要提供 IoC 依赖注入功能的支持。由 Beans 模块、Core 核心模块、Context 上下文模块和 SpEL 表达式语言模块组成,没有这些核心容器,也不可能有 AOP、Web 等上层的功能.
对应源码模块如下:
对应源码模块如下:
对应源码模块:
对应源码模块如下:
Spring 包含了多个功能模块(上面刚刚提到过),其中最重要的是 Spring-Core(主要提供 IoC 依赖注入功能的支持) 模块, Spring 中的其他模块(比如 Spring MVC)的功能实现基本都需要依赖于该模块.
Spring MVC 是 Spring 中的一个很重要的模块,主要赋予 Spring 快速构建 MVC 架构的 Web 程序的能力。MVC 是模型(Model)、视图(View)、控制器(Controller)的简写,其核心思想是通过将业务逻辑、数据、显示分离来组织代码.
使用 Spring 进行开发各种配置过于麻烦比如开启某些 Spring 特性时,需要用 XML 或 Java 进行显式配置。于是,Spring Boot 诞生了! 。
Spring 旨在简化 J2EE 企业应用程序开发。Spring Boot 旨在简化 Spring 开发(减少配置文件,开箱即用!).
Spring Boot 只是简化了配置,如果你需要构建 MVC 架构的 Web 程序,你还是需要使用 Spring MVC 作为 MVC 框架,只是说 Spring Boot 帮你简化了 Spring MVC 的很多配置,真正做到开箱即用! 。
这里只是表示这是Spring第一个项目,以HelloWorld作为标注。实际需求是获取 用户列表信息,并打印执行日志 。
案例源码点击这里 。
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
<spring.version>5.3.37</spring.version>
<aspectjweaver.version>1.9.6</aspectjweaver.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-core</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-beans</artifactId>
<version>${spring.version}</version>
</dependency>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>${aspectjweaver.version}</version>
</dependency>
</dependencies>
public class User {
private String name;
private int age;
public User(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
public class UserDaoImpl{
public List<User> findUserList() {
return Collections.singletonList(new User("seven", 18));
}
}
public class UserServiceImpl {
private UserDaoImpl userDao;
public void setUserDao(UserDaoImpl userDao) {
this.userDao = userDao;
}
public List<User> findUserList() {
return userDao.findUserList();
}
}
@Aspect
public class LogAspect {
@Around("execution(* com.seven.springhelloworldxml.service.*.*(..))")
public Object businessService(ProceedingJoinPoint pjp) throws Throwable {
// get attribute through annotation
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
System.out.println("execute method: " + method.getName());
// continue to process
return pjp.proceed();
}
}
<?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">
<bean id="userDao" class="com.seven.springhelloworldxml.dao.UserDaoImpl">
<!-- additional collaborators and configuration for this bean go here -->
</bean>
<bean id="userService" class="com.seven.springhelloworldxml.service.UserServiceImpl">
<property name="userDao" ref="userDao"/>
<!-- additional collaborators and configuration for this bean go here -->
</bean>
</beans>
<?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"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
">
<context:component-scan base-package="com.seven.springhelloworldxml" />
<aop:aspectj-autoproxy/>
<bean id="logAspect" class="com.seven.springhelloworldxml.aspects.LogAspect">
<!-- configure properties of aspect here as normal -->
</bean>
<!-- more bean definitions for data access objects go here -->
</beans>
public class APP {
public static void main(String[] args) {
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("aspects.xml", "spring.xml");
// retrieve configured instance
UserServiceImpl service = context.getBean("userService", UserServiceImpl.class);
// use configured instance
List<User> userList = service.findUserList();
// print info from beans
userList.forEach(a -> System.out.println(a.getName() + "," + a.getAge()));
}
}
运行结果:
查询用户(service通过调用dao查询pojo),本质上就是如何创建User/Dao/Service?
UserDaoImpl userDao = new UserDaoImpl();
UserSericeImpl userService = new UserServiceImpl();
userService.setUserDao(userDao);
List<User> userList = userService.findUserList();
Bean的创建和使用分离了.
// create and configure beans
ApplicationContext context = new ClassPathXmlApplicationContext("aspects.xml", "spring.xml");
// retrieve configured instance
UserServiceImpl service = context.getBean("userService", UserServiceImpl.class);
// use configured instance
List<User> userList = service.findUserList();
更进一步,便能理解为何会有如下的知识点了:
第二个需求:给Service所有方法调用添加日志(调用方法时),本质上是解耦问题; 。
public List<User> findUserList() {
System.out.println("execute method findUserList");
return this.userDao.findUserList();
}
/**
* aspect for every methods under service package.
*/
@Around("execution(* com.seven.springhelloworldxml.service.*.*(..))")
public Object businessService(ProceedingJoinPoint pjp) throws Throwable {
// get attribute through annotation
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
System.out.println("execute method: " + method.getName());
// continue to process
return pjp.proceed();
}
更进一步,便能理解为何会有如下的知识点了:
案例源码点击这里 。
在前文的例子中, 通过xml配置方式实现的,这种方式实际上比较麻烦; 我通过Java配置进行改造:
@EnableAspectJAutoProxy
@Configuration
public class BeansConfig {
/**
* @return user dao
*/
@Bean("userDao")
public UserDaoImpl userDao() {
return new UserDaoImpl();
}
/**
* @return user service
*/
@Bean("userService")
public UserServiceImpl userService() {
UserServiceImpl userService = new UserServiceImpl();
userService.setUserDao(userDao());
return userService;
}
/**
* @return log aspect
*/
@Bean("logAspect")
public LogAspect logAspect() {
return new LogAspect();
}
}
public class APP {
public static void main(String[] args) {
// create and configure beans
ApplicationContext context = new AnnotationConfigApplicationContext(BeansConfig.class);
// retrieve configured instance
UserServiceImpl service = context.getBean("userService", UserServiceImpl.class);
// use configured instance
List<User> userList = service.findUserList();
// print info from beans
userList.forEach(a -> System.out.println(a.getName() + "," + a.getAge()));
}
}
这里简单提一下实现原理:
当应用启动时,Spring框架会使用Java的反射API来检查所有带有@Configuration 注解的类(这里不懂的可以看下注解实现的原理)。Spring框架内置了一个注解处理器ConfigurationClassPostProcessor,它是BeanFactoryPostProcessor 的一个实现.
接着ConfigurationClassPostProcessor 会在容器初始化时被调用,它会查找所有带有@Configuration 注解的类,并解析这些类中定义的@Bean 方法.
BeanDefinition:对于每个@Configuration 类,Spring会为其中的每个@Bean 方法生成一个BeanDefinition 对象。这些BeanDefinition 对象会包含创建和配置Bean所需的所有信息.
处理嵌套配置:如果一个@Configuration 类中包含了另一个@Configuration 类的引用,ConfigurationClassPostProcessor 会递归地处理这些嵌套的配置类.
注册BeanDefinition: 一旦所有的BeanDefinition 被创建,它们会被注册到Spring容器的BeanFactory 中。这样,Spring容器就可以在需要时创建和注入这些Bean.
代理配置类: 为了支持嵌套配置类和循环依赖等特性,Spring会为每个@Configuration 类创建一个代理,这个代理会在运行时处理相关的逻辑.
案例源码点击这里 。
更进一步,Java 5开始提供注解支持,Spring 2.5 开始完全支持基于注解的配置并且也支持JSR250 注解。在Spring后续的版本发展倾向于通过注解和Java配置结合使用. 。
@EnableAspectJAutoProxy
@Configuration
public class BeansConfig {
}
@Repository
public class UserDaoImpl{
public List<User> findUserList() {
return Collections.singletonList(new User("seven", 18));
}
}
@Service
public class UserServiceImpl {
@Autowired
private UserDaoImpl userDao;
public List<User> findUserList() {
return userDao.findUserList();
}
}
@Component
@Aspect
public class LogAspect {
@Around("execution(* com.seven.springhelloworldanno.service.*.*(..))")
public Object businessService(ProceedingJoinPoint pjp) throws Throwable {
// get attribute through annotation
Method method = ((MethodSignature) pjp.getSignature()).getMethod();
System.out.println("execute method: " + method.getName());
// continue to process
return pjp.proceed();
}
}
public static void main(String[] args) {
// create and configure beans
ApplicationContext context = new AnnotationConfigApplicationContext("com.seven.springhelloworldanno");
// retrieve configured instance
UserServiceImpl service = context.getBean(UserServiceImpl.class);
// use configured instance
List<User> userList = service.findUserList();
// print info from beans
userList.forEach(a -> System.out.println(a.getName() + "," + a.getAge()));
}
这里要提一嘴的是,现在大多数的Spring项目,基本都是这种方式。主要步骤就是: 1、对类添加@Component相关的注解,比如@Controller,@Service,@Repository 2、设置ComponentScan的basePackage, 比如在xml文件里设置<context:component-scan base-package='com.seven.springframework'>, 或者在配置类中设置@ComponentScan("com.seven.springframework")注解,或者 直接在APP类中 new AnnotationConfigApplicationContext("com.seven.springframework")指定扫描的basePackage. 。
Springboot实际上通过约定大于配置的方式,使用xx-starter统一的对Bean进行默认初始化,用户只需要很少的配置就可以进行开发了.
Java面试题专栏已上线,欢迎访问.
那么可以私信我,我会尽我所能帮助你.
最后此篇关于全网最详细的Spring入门教程的文章就讲到这里了,如果你想了解更多关于全网最详细的Spring入门教程的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
目录 进程 其他相关概念 创建线程的两种方式 为什么使用start()方法而不直接使用run()方法 start()方法底层
CURL状态码列表 状态码 状态原因 解释 0 正常访问
ODBC连接类函数 odbc_connect函数:打开一个ODBC连接 odbc_close函数:关闭一个已经打开的ODBC连接 odbc_close_all函数:关闭所有已经打开的ODBC连
作为标题,如何计算从纪元1900到现在使用boost的持续时间? 编辑:很抱歉以前的问题太短。我将再次描述我的问题。 我有关于将生日另存为整数的问题。我创建了四个函数,用法如下: ptime转换为整数
前言 在Java中,有一个常被忽略 但 非常重要的关键字Synchronized今天,我将详细讲解 Java关键字Synchronized的所有知识,希望你们会喜欢 目录 1. 定义 J
详细 JVM 垃圾收集日志的时间戳是收集的开始还是结束? 2016-08-09T21:04:19.756-0400: 224890.317: [GC Desired survivor size 167
我在“Master-Detail”概念上苦苦挣扎,除了一点点(但很重要)的细微差别外,几乎所有东西都按预期工作。我应该在 Storyboard上更改什么以在详细信息 View (屏幕截图底部的右上角)
我希望能够显示表格的详细 View ,但不推送新屏幕,而只显示表格所在的详细 View 。 设置它的最佳方式是什么......如果真的可行的话? ---------------------------
我在我的博客中为我的帖子使用了详细 View ,每篇帖子都有评论,所以我想对它们进行分页,但我不知道该怎么做,因为我请求了帖子模型。我知道如何在功能 View 中执行此操作,但不知道如何在详细 Vie
在下面的代码中,与 pm 对齐,该行是否会 move 整个内存并将其分配给 pm,或者它只会 move p 指向的内存而不是整个数组? int main() { int*
1·下载 https://dev.mysql.com/downloads/mysql/ 2·安装服务 1)管理员运行cmd 2)D: 3)cd D:\mysql
今天以前一直用的SQL Server 2005做开发,偶尔也用MySQL,现入手公司项目,用到SQL Server 2008,于是乎必须安装它,免得出现其他很纠结的小问题,现将自己安装图解分享如下:
1. crontab命令选项 复制代码 代码如下: #crontab -u <-l, -r, -e> -u指定一个用
我们有一个 WPF 应用程序,它有一个主窗口/详细信息窗口,两者都是 WPF 数据网格。当您在上部数据网格中选择一行时,详细信息将显示在下部数据网格中。我想知道从 UI 的角度来看是否有任何关于如何处
在可视化 Perforce 客户端 (p4v) 中有一个选项: 显示文件操作的 p4 命令输出 启用后,在日志 Pane 中,我可以看到这样的详细日志记录: p4 sync /Users/az/ftp
在其他服务器上设置测试环境后,在几个API调用中出现错误。 99%肯定这是MySQL的事情,但是返回的错误根本没有帮助: global name 'sys' is not defined" 我已经导入
我正在维护一个通用的 iOS 应用程序,其开发已开始于 iOS 6。我正在为 iOS 7 更新 UI。现在我遇到了应用程序的 iPad 部分的奇怪问题。这部分遵循使用 UISplitViewContr
我希望我能正确描述这种情况。当它发生时很容易在屏幕上看到,但很难用语言解释,但我会尽力而为。 我有一个带有固定主视图 (UITableView) 和两个详细 View 之一的 UISplitViewC
我尝试在 eclipse 和 intelliJ 参数中使用垃圾收集记录器来配置简单的测试程序。尝试了不同类型的配置,但尚未创建日志文件。 -XX:+PrintGCDetails -XX:+PrintG
正如您所知,.cap 文件中的 java 小程序的输出文件格式必须通过智能卡读卡器/写卡器(如 ACR122 或任何其他读卡器)部署到 java 卡,而且我相信 java 卡与 java 卡之间的部署
我是一名优秀的程序员,十分优秀!