- Servlet:Servlet是一种Java技术,用于扩展Web服务器或应用服务器的能力,以便能够处理客户端(通常是浏览器)发送来的请求,并返回响应。Servlet运行于服务器端。
- Tomcat:Tomcat是一个开源的Web服务器和Servlet容器,它支持Java Servlet和JavaServer Pages (JSP) 技术。Tomcat可以作为独立的Web服务器运行,也可以与其他Web服务器集成。
- Spring Boot:Spring Boot是一个基于Spring框架的快速开发工具,旨在简化新Spring应用程序的初始设置和配置。它允许开发者快速搭建新的项目,而无需过多关注配置细节。
请求流程详解
- 客户端发起请求:当你在浏览器中输入一个URL并访问时,这个请求首先会被发送到Web服务器(比如Tomcat)。
- 请求解析:Web服务器接收到请求后,会解析请求信息,这包括请求的方法类型(GET, POST等)、请求路径Params、请求头Headers、请求体Body等信息。
- 请求转发给Servlet:Web服务器将解析好的请求封装成
HttpServletRequest
对象,并创建一个HttpServletResponse
对象准备存放响应信息。这两个对象一起被传递给匹配的Servlet(在Spring Boot中通常是DispatcherServlet
)。- 请求处理:
DispatcherServlet
接收到请求后,会查找与请求URL匹配的Controller方法。这一步涉及到多个组件,例如HandlerMapping用于确定哪个Controller方法应该处理请求,HandlerAdapter负责调用该方法。- 视图解析与响应生成:Controller方法处理完请求后,可能会返回一个ModelAndView对象或者直接返回一个字符串标识视图名。
DispatcherServlet
会使用ViewResolver解析视图名,找到相应的视图实现,并通过这个视图生成最终要返回给客户端的HTML页面或者其他形式的数据。- 响应发送回客户端:生成的响应数据会被写入到
HttpServletResponse
对象中,然后由Web服务器发送回客户端。
请求
各类请求参数的接收及封装
Postman
简单参数
只需要保证请求的参数名与control方法的形参名称保持一致,则接收成功
//springboot方式
@RequestMapping("/simpleParam")
public String simpleParam(String name, Integer age){
System.out.println(name+":"+age);
return "OK";
}
post请求是在请求体中设置参数
@RequestParam中的required属性默认为true,代表该请求参数必须传递,如果不传递将报错。如果该参数是可选的,可以将required属性设置为false。
简单参数只能传递少量参数,多的话可以用实体参数包装
实体参数
@RequestMapping("/simplePojo")
public String simplePojo(User user){
System.out.println(user);
return "OK";
}
实体对象参数
规则:请求参数名与形参对象属性名相同,即可直接通过POJO接收
先封装一个实体对象,嵌套的话就一个属性一个属性封装
先定义一个实体类Address,快速生成get、set方法以及toString方法即标准JavaBean
如果是一个复杂实体对象,只需要按照层次结构对应起来就可以了
服务端请求参数的接收方式有两种:数组、集合
数组集合参数
只需要在形参当中,声明一个数组,数组的名字需要和上面的请求参数名保持一致
@RequestMapping("/arrayParam")
public String arrayParam(String[] hobby){
System.out.println(arrays.toString(hobby));
return "OK";
}
要在形参的list集合前面加上一个注解@RequestParam 绑定参数关系,因为在默认情况下,这多个值会封装在数组当中
@RequestMapping("/listParam")
public String listParam(@RequestParam List<String> hobby){
System.out.println(hobby);
return "OK";
}
使用数组以及集合的形式来接收前端传递过来的多个请求参数值
日期参数
@RequestMapping("/dateParam")
public String dateParam(@DateTimeFormat(pattern="yyyy-MM-dd HH:mm:ss") LocalDateTime updateTime){
System.out.println(updateTime);
return "OK";
}
主要是通过在形参前面加一个注解@DateTimeFormat来指定传递的参数格式
接口请求的常用方式两种GET/POST
GET与POST的区别
① 长度。GET有长度限制,POST没有长度限制。
② 安全性。GET通常是将参数显示在URL地址中,可以被看见,不是那么安全;POST是将参数写入body中,不能被看见,更安全。
③ 作用。 GET通常作用于从数据库中读取数据;POST则是将数据提交/更新于数据库中。
Json参数
Json格式的参数在前后端异步交互的时候使用的非常多
1.在postman发送请求的时候,如何传递json格式的参数
要想发送一个请求,并且传递json格式的请求数据,我们需要将请求方式设置为host,因为Json格式的请求数据是需要放在请求当中携带到服务器的
要选择的是raw
JSON当中所有的key都必须使用双引号将其引起来
2.在服务端control当中,怎么来接收json格式的请求参数
一般会通过实体对象来接收,通过user来接收传递过来的JSON格式的数据
@RequestBody这个注解就可以将json格式的请求数据封装到一个实体对象当中
@RequestMapping("/jsonParam")
public String jsonParam(@RequestBody User user){
System.out.println(user);
return "OK";
}
路径参数
在前面的学习里面 都加了一个注解@RequestMApping,用来指定方法的请求路径
参数已经成为了url的一部分
同时也是我们给服务端所传递的请求参数
重点学习:在服务端control的方法当中,怎么样来获取路径参数
接收路径参数同样也需要定一个方法,也需要加上@RequestMapping
动态设置路径
@PathVariable用来指定要获取的路径参数,并且把路径参数的id绑定给我们的方法形参id
路径参数id需要与方法形参名称id保持一致
@RequestMapping("/path/{id}")
public String pathParam(@PathVarible Integer id){
System.out.println(id);
return "OK";
}
@RequestMapping("/path/{id}/{name}")
public String pathParam(@PathVarible Integer id,@PathVarible String name){
System.out.println(id);
System.out.println(name);
return "OK";
}
响应
control程序的核心职责就是接收请求,然后设置响应
@ResponseBody
元注解是注解的注解,用于修饰自定义注解的行为。
我们在controller当中定义的每一个对外暴露的方法 都称之为功能接口
上面的路径就是接口的访问路径
项目开发中需要的开发文档就是描述功能接口,它的请求路径是什么、请求参数是什么、以及它响应的数据是什么
在Java中,
Object
类是所有类的超类(即基类)。每个类都直接或间接地继承自Object
类。这意味着所有对象都具有Object
类中定义的方法。以下是Object
类的一些重要方法和概念:Object 类的主要方法
toString()
:
- 返回对象的字符串表示形式。默认实现返回对象的类名和哈希码,但通常会被子类重写以提供更有意义的字符串表示。
- 示例:
public String toString() { return getClass().getName() + "@" + Integer.toHexString(hashCode()); }
hashCode()
:
- 返回对象的哈希码,这是一个整数。哈希码用于哈希表(如
HashMap
)中快速查找对象。- 示例:
public int hashCode() { return System.identityHashCode(this); }
equals(Object obj)
:
- 判断当前对象是否等于指定的对象。默认实现是基于对象的引用比较(即是否是同一个对象),但通常会被子类重写以提供基于内容的比较。
- 示例:
public boolean equals(Object obj) { return (this == obj); }
getClass()
:
- 返回对象的运行时类。
- 示例:
public final native Class<?> getClass();
finalize()
:
- 当垃圾回收器确定没有对该对象的更多引用时,将调用此方法。此方法主要用于释放系统资源或执行清理工作。注意,从Java 9开始,
finalize()
方法被标记为已弃用。- 示例:
protected void finalize() throws Throwable { // 清理工作 }
clone()
:
- 创建并返回当前对象的一个副本。要使对象可克隆,类必须实现
Cloneable
接口,并重写clone()
方法。- 示例:
protected Object clone() throws CloneNotSupportedException { return super.clone(); }
wait()
、notify()
和notifyAll()
:
- 这些方法用于线程间的通信。它们必须在同步块中调用。
wait()
:使当前线程等待,直到其他线程调用notify()
或notifyAll()
方法。notify()
:唤醒在此对象监视器上等待的单个线程。notifyAll()
:唤醒在此对象监视器上等待的所有线程。- 示例:
public final void wait() throws InterruptedException { // 等待 } public final void notify() { // 唤醒一个线程 } public final void notifyAll() { // 唤醒所有线程 }
Object 类的重要概念
多态性:
- 由于所有类都继承自
Object
类,因此可以使用Object
类型的引用指向任何对象。这种特性称为多态性。- 示例:
Object obj = new String("Hello");
类型转换:
- 可以使用类型转换将
Object
类型的引用转换回具体的子类类型。- 示例:
Object obj = new String("Hello"); String str = (String) obj;
对象比较:
- 使用
equals()
方法进行内容比较,而不是使用==
进行引用比较。- 示例:
String str1 = new String("Hello"); String str2 = new String("Hello"); System.out.println(str1.equals(str2)); // true System.out.println(str1 == str2); // false
Object
类是Java中所有类的根类,提供了许多基本方法,这些方法在对象的生命周期管理和多态性中起着重要作用。理解Object
类的方法和概念对于编写高效、健壮的Java程序非常重要。
一个案例
resource这个目录存放的是一些其他的资源文件
对于String boot项目来讲,是可以添加前端页面的,但其存储目录是有规范的
classpath指的是类路径,对maven项目来说,resource目录就是一个类路径
@RestController
注解是 Spring 框架提供的一个组合注解,它结合了@Controller
和@ResponseBody
注解的功能。使用@RestController
注解的类通常用于创建 RESTful Web 服务,这些服务直接返回 JSON 或 XML 数据,而不是视图页面。何时使用
@RestController
注解
创建 RESTful API:
- 当你需要创建一个 RESTful Web 服务时,通常会使用
@RestController
注解。这种服务通常用于提供数据接口,客户端(如浏览器、移动应用等)通过 HTTP 请求获取数据。- 示例:
@RestController public class UserController { @GetMapping("/users") public List<User> getAllUsers() { // 返回用户列表 return userService.getAllUsers(); } @PostMapping("/users") public User createUser(@RequestBody User user) { // 创建用户 return userService.createUser(user); } }
直接返回数据而不是视图:
- 如果你的控制器方法需要直接返回数据(如 JSON 或 XML),而不是跳转到视图页面,那么使用
@RestController
是最合适的选择。- 示例:
@RestController public class ProductController { @GetMapping("/products/{id}") public Product getProductById(@PathVariable Long id) { // 返回指定ID的产品 return productService.getProductById(id); } }
简化开发:
- 使用
@RestController
可以简化开发过程,因为你不需要在每个方法上单独添加@ResponseBody
注解。所有的方法默认都会返回数据而不是视图。- 示例:
@RestController public class OrderController { @GetMapping("/orders") public List<Order> getAllOrders() { // 返回订单列表 return orderService.getAllOrders(); } @GetMapping("/orders/{id}") public Order getOrderById(@PathVariable Long id) { // 返回指定ID的订单 return orderService.getOrderById(id); } }
不使用
@RestController
的场景
返回视图页面:
- 如果你的控制器方法需要返回视图页面(如 JSP、Thymeleaf 模板等),则应该使用
@Controller
注解,而不是@RestController
。- 示例:
@Controller public class HomeController { @GetMapping("/") public String home() { // 返回首页视图 return "home"; } }
混合使用:
- 如果你在同一个控制器中既有返回数据的方法,也有返回视图的方法,可以使用
@Controller
注解,并在需要返回数据的方法上单独添加@ResponseBody
注解。- 示例:
@Controller public class MixedController { @GetMapping("/api/data") @ResponseBody public Data getData() { // 返回数据 return dataService.getData(); } @GetMapping("/view") public String getView() { // 返回视图 return "view"; } }
- 使用
@RestController
:当你需要创建 RESTful API,直接返回数据而不是视图页面时。- 使用
@Controller
:当你需要返回视图页面,或者在一个控制器中混合使用返回数据和视图的方法时。
getClassLoader()
方法是 Java 中Class
类提供的一个方法,用于获取当前类的类加载器。类加载器(ClassLoader)是 Java 虚拟机(JVM)的一部分,负责将类文件加载到内存中,并对类进行初始化。了解类加载器的工作原理和使用getClassLoader()
方法可以帮助你更好地管理类的加载和资源的访问。
getClassLoader()
方法详解方法签名
public ClassLoader getClassLoader()
返回值
- 返回当前类的类加载器。如果当前类是由引导类加载器(Bootstrap ClassLoader)加载的,则返回
null
。作用
- 获取当前类的类加载器,以便于进行类加载、资源文件的加载等操作。
类加载器层次结构
Java 的类加载器分为以下几个层次:
引导类加载器(Bootstrap ClassLoader):
- 负责加载核心的 Java 类库(如
rt.jar
),这些类库位于$JAVA_HOME/jre/lib
目录下。- 引导类加载器不是由 Java 编写的,而是由原生代码实现的。
- 无法通过
getClassLoader()
方法获取到引导类加载器,返回值为null
。扩展类加载器(Extension ClassLoader):
- 负责加载
$JAVA_HOME/jre/lib/ext
目录下的扩展类库。- 扩展类加载器是
sun.misc.Launcher$ExtClassLoader
的实例。系统类加载器(Application ClassLoader):
- 负责加载应用程序类路径(classpath)下的类。
- 系统类加载器是
sun.misc.Launcher$AppClassLoader
的实例。示例代码
获取当前类的类加载器
public class ClassLoaderExample { public static void main(String[] args) { // 获取当前类的类加载器 ClassLoader classLoader = ClassLoaderExample.class.getClassLoader(); System.out.println("Current class loader: " + classLoader); // 获取系统的类加载器 ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); System.out.println("System class loader: " + systemClassLoader); // 获取引导类加载器加载的类的类加载器 ClassLoader stringClassLoader = String.class.getClassLoader(); System.out.println("String class loader: " + stringClassLoader); // 输出 null } }
加载资源文件
public class ResourceLoaderExample { public static void main(String[] args) { // 获取当前类的类加载器 ClassLoader classLoader = ResourceLoaderExample.class.getClassLoader(); // 加载资源文件 InputStream resourceAsStream = classLoader.getResourceAsStream("config.properties"); if (resourceAsStream != null) { Properties properties = new Properties(); try { properties.load(resourceAsStream); System.out.println("Property: " + properties.getProperty("name")); } catch (IOException e) { e.printStackTrace(); } } else { System.out.println("Resource not found"); } } }
注意事项
类加载器的委托模型:
- Java 类加载器采用了委托模型。当一个类加载器收到类加载请求时,它首先不会自己去加载这个类,而是把这个请求委派给父类加载器去完成,每一层的类加载器都是如此,因此所有的类加载请求最终都应该传送到最顶层的引导类加载器中,只有当父类加载器反馈自己无法加载这个类时,子类加载器才会尝试自己去加载。
类加载器的作用域:
- 每个类加载器都有自己的作用域,只能加载其类路径下的类。例如,系统类加载器只能加载应用程序类路径下的类,而扩展类加载器只能加载扩展类路径下的类。
类加载器的唯一性:
- 同一个类加载器加载的类被认为是相同的,即使类的字节码来自不同的文件。因此,类加载器在类的唯一性判断中起到了关键作用。
通过理解和使用
getClassLoader()
方法,你可以更好地控制类的加载过程和资源的访问,这对于开发复杂的 Java 应用程序非常有用。
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();详解这行代码
这行代码的作用是从类路径中加载一个名为
emp.xml
的资源文件,并将其路径转换为一个字符串。让我们逐步解析这行代码的各个部分:代码解析
String file = this.getClass().getClassLoader().getResource("emp.xml").getFile();
this.getClass()
:
- 这是一个 Java 关键字,表示当前对象的引用。
getClass()
方法返回当前对象的Class
对象,该对象代表了当前对象所属的类。
getClass().getClassLoader()
:
getClassLoader()
方法返回当前类的类加载器。- 类加载器负责将类文件加载到 JVM 中。对于大多数应用程序类,这通常是系统类加载器(
AppClassLoader
)。
getClassLoader().getResource("emp.xml")
:
getResource(String name)
方法从类路径中查找并返回一个URL
对象,表示指定名称的资源文件。- 参数
"emp.xml"
是资源文件的名称。类加载器会在类路径中搜索这个文件。类路径通常包括项目的src/main/resources
目录(对于 Maven 项目)或resources
目录(对于其他构建工具)。
getResource("emp.xml").getFile()
:
getResource("emp.xml")
返回一个URL
对象。getFile()
方法从URL
对象中提取文件路径部分,返回一个字符串。- 返回的路径可能是一个绝对路径,也可能是一个带有
%20
等编码的路径(因为URL
中的空格和其他特殊字符会被编码)。
empList.stream().forEach(emp->{});详解这行代码
这行代码使用了 Java 8 中的流(Stream)API 和 Lambda 表达式来遍历一个
List
集合中的所有元素,并对每个元素执行某些操作。让我们详细解析这行代码的各个部分:代码解析
empList.stream().forEach(emp -> {});
empList
:
- 这是一个
List
集合,假设它存储了多个Employee
对象。
stream()
:
stream()
方法是Collection
接口的一个默认方法,它返回一个流对象(Stream
)。流是处理集合的一种方式,提供了许多用于过滤、映射、排序等操作的方法。- 流对象允许你以声明式的方式处理数据,而不需要显式地编写循环和临时变量。
forEach(emp -> {})
:
forEach
方法是Stream
接口的一个终端操作,用于遍历流中的每个元素,并对每个元素执行给定的操作。emp -> {}
是一个 Lambda 表达式,表示一个函数式接口的实现。在这个例子中,forEach
方法接受一个Consumer
函数式接口的实例,该接口定义了一个void accept(T t)
方法。emp
是 Lambda 表达式的参数,表示当前遍历到的元素。{}
是 Lambda 表达式的主体部分,表示对emp
执行的操作。在这个例子中,主体部分为空,即没有任何操作。完整示例
假设我们有一个
Employee
类和一个包含多个Employee
对象的List
集合:import java.util.Arrays; import java.util.List; class Employee { private String name; private int age; public Employee(String name, int age) { this.name = name; this.age = age; } public String getName() { return name; } public int getAge() { return age; } @Override public String toString() { return "Employee{name='" + name + "', age=" + age + "}"; } } public class StreamExample { public static void main(String[] args) { List<Employee> empList = Arrays.asList( new Employee("Alice", 30), new Employee("Bob", 25), new Employee("Charlie", 35) ); // 使用流和 forEach 方法遍历 empList empList.stream().forEach(emp -> { // 在这里可以对每个 emp 执行操作 System.out.println(emp); }); } }
解释
创建
Employee
类:
Employee
类有两个属性:name
和age
,以及相应的构造方法和 getter 方法。创建
empList
集合:
- 使用
Arrays.asList
方法创建一个包含多个Employee
对象的List
集合。使用流和
forEach
方法遍历empList
:
empList.stream()
将empList
转换为一个流对象。forEach(emp -> { System.out.println(emp); })
遍历流中的每个Employee
对象,并调用System.out.println(emp)
方法打印每个对象的信息。注意事项
Lambda 表达式的主体部分:
- 如果主体部分只有一条语句,可以省略大括号
{}
:empList.stream().forEach(emp -> System.out.println(emp));
方法引用:
- 如果 Lambda 表达式只是调用一个已有的方法,可以使用方法引用:
empList.stream().forEach(System.out::println);
副作用:
- 在
forEach
方法中执行的操作可能会有副作用,例如修改共享状态。为了避免并发问题,尽量避免在流操作中修改外部状态。通过这种方式,你可以简洁高效地遍历集合并执行所需的操作。
Lambda表达式的介绍
Lambda 表达式是 Java 8 引入的一项重要特性,它允许你以更简洁的方式编写函数式接口的实现。Lambda 表达式使得代码更加简洁、易读,并且支持函数式编程风格。下面是对 Lambda 表达式的详细介绍:
什么是 Lambda 表达式?
Lambda 表达式是一种匿名函数,它可以没有名称,但有参数列表、函数主体、返回类型,同时它也支持类型推断。Lambda 表达式的主要用途是实现函数式接口(即只有一个抽象方法的接口)。
Lambda 表达式的语法
Lambda 表达式的语法如下:
(parameters) -> expression
(parameters) -> { statements; }
组件解释
参数列表:
- 参数列表放在圆括号
( )
中,参数类型可以省略,因为编译器可以自动推断。- 如果只有一个参数,圆括号可以省略。
- 如果没有参数,需要使用空的圆括号
()
。箭头符号:
->
是箭头符号,用于分隔参数列表和函数主体。函数主体:
- 函数主体可以是一个表达式或一个代码块。
- 如果函数主体是一个表达式,可以直接写表达式,不需要大括号
{ }
。- 如果函数主体是一个代码块,需要用大括号
{ }
包围,并且可以包含多条语句。示例
示例 1:简单的 Lambda 表达式
// 定义一个函数式接口 @FunctionalInterface interface MyFunction { int apply(int x); } public class LambdaExample { public static void main(String[] args) { // 使用 Lambda 表达式实现 MyFunction 接口 MyFunction square = (x) -> x * x; // 调用 apply 方法 int result = square.apply(5); System.out.println("Square of 5 is: " + result); // 输出: Square of 5 is: 25 } }
示例 2:带多个参数的 Lambda 表达式
// 定义一个函数式接口 @FunctionalInterface interface MyBinaryOperator { int apply(int x, int y); } public class LambdaExample { public static void main(String[] args) { // 使用 Lambda 表达式实现 MyBinaryOperator 接口 MyBinaryOperator add = (x, y) -> x + y; // 调用 apply 方法 int result = add.apply(3, 4); System.out.println("Sum of 3 and 4 is: " + result); // 输出: Sum of 3 and 4 is: 7 } }
示例 3:带无参的 Lambda 表达式
// 定义一个函数式接口 @FunctionalInterface interface MySupplier { String get(); } public class LambdaExample { public static void main(String[] args) { // 使用 Lambda 表达式实现 MySupplier 接口 MySupplier greeting = () -> "Hello, World!"; // 调用 get 方法 String message = greeting.get(); System.out.println(message); // 输出: Hello, World! } }
示例 4:带代码块的 Lambda 表达式
// 定义一个函数式接口 @FunctionalInterface interface MyConsumer { void accept(String message); } public class LambdaExample { public static void main(String[] args) { // 使用 Lambda 表达式实现 MyConsumer 接口 MyConsumer printMessage = (message) -> { System.out.println("Processing message: " + message); System.out.println("Message processed."); }; // 调用 accept 方法 printMessage.accept("Hello, Lambda!"); // 输出: // Processing message: Hello, Lambda! // Message processed. } }
常见的函数式接口
Java 8 提供了一些常用的函数式接口,它们位于
java.util.function
包中:
Function<T, R>
:接受一个参数,返回一个结果。Function<String, Integer> lengthFunction = String::length; int length = lengthFunction.apply("Hello");
Predicate<T>
:接受一个参数,返回一个布尔值。Predicate<String> isEmpty = String::isEmpty; boolean result = isEmpty.test("");
Consumer<T>
:接受一个参数,不返回结果。Consumer<String> printMessage = System.out::println; printMessage.accept("Hello, World!");
Supplier<T>
:不接受参数,返回一个结果。Supplier<String> greeting = () -> "Hello, World!"; String message = greeting.get();
BiFunction<T, U, R>
:接受两个参数,返回一个结果。BiFunction<Integer, Integer, Integer> add = (x, y) -> x + y; int sum = add.apply(3, 4);
优点
- 简洁性:
- Lambda 表达式使代码更加简洁、易读。
- 函数式编程支持:
- 支持函数式编程风格,使得代码更加模块化和灵活。
- 并行处理:
- 结合流(Stream)API,可以轻松实现并行处理,提高性能。
通过使用 Lambda 表达式,你可以更高效地编写和维护代码,特别是在处理集合和并行任务时。
前端代码在页面加载的时候,通过vue的钩子方法发起了一个异步请求来加载数据,在成功的回调函数当中,先是判定了一下响应回来的code的值
分层解耦
三层架构
在进行软件设计以及软件开发时,需要尽量让每个接口类或者是方法只做一件事情,职责单一,即单一职责原则,优点会使接口类以及方法的复杂度更低、可读性更强、拓展性更好,更利于后期的维护
Dao层要想灵活的去获取数据,可以通过面向接口的方式进行编程
分层解耦
仅仅存放与员工相关的逻辑处理即为高内聚
对象怎么样交给容器来管理
容器怎么样为我们的程序提供它所依赖的资源
这个容器我们叫spring容器,或者ioc容器
IOC & DI入门
(1)加上注解@Component //将当前类交给IOC容器管理,成为IOC容器中的bean
(2)在成员变量上加上注解@Autowired//运行时,IOC容器会提供该类型的bean对象,并赋值给该变量 此过程也称为依赖注入
@Component是干什么的
@Component
是 Spring 框架中的一个注解,用于标记一个 Java 类为 Spring 管理的 Bean。Spring 容器会自动检测这些类,并将它们注册为 Bean,从而可以在应用程序中通过依赖注入(Dependency Injection, DI)来使用这些 Bean。主要用途
标记为 Spring Bean:
@Component
注解告诉 Spring 容器这是一个组件,需要被管理和注入。- 这个注解可以应用于任何普通的 Java 类。
自动扫描和注册:
- 当你使用
@Component
注解标记一个类后,Spring 容器会在启动时自动扫描这些类,并将它们注册为 Bean。- 这通常需要配合
@ComponentScan
注解来指定扫描的包路径。示例
示例 1:基本用法
假设我们有一个简单的服务类
MyService
,我们希望 Spring 容器管理它:import org.springframework.stereotype.Component; @Component public class MyService { public void doSomething() { System.out.println("Doing something..."); } }
示例 2:配合
@ComponentScan
使用在 Spring Boot 应用程序的主类中,通常会使用
@SpringBootApplication
注解,它包含了@ComponentScan
注解,会自动扫描主类所在包及其子包中的所有@Component
注解的类。import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.SpringApplication; import org.springframework.boot.autoconfigure.SpringBootApplication; @SpringBootApplication public class MyApplication { @Autowired private MyService myService; public static void main(String[] args) { SpringApplication.run(MyApplication.class, args); } public void run() { myService.doSomething(); // 调用 MyService 的方法 } }
其他相关注解
除了
@Component
,Spring 还提供了几个专门用于标记不同类型的 Bean 的注解:
@Service
:
- 用于标记业务逻辑层的类。
- 示例:
@Service public class UserService { // 业务逻辑方法 }
@Repository
:
- 用于标记数据访问层的类,通常用于 DAO(Data Access Object)。
- 示例:
@Repository public class UserRepository { // 数据访问方法 }
@Controller
:
- 用于标记控制层的类,通常用于处理 HTTP 请求的控制器。
- 示例:
@Controller public class UserController { // 控制器方法 }
注意事项
包扫描路径:
- 确保
@ComponentScan
注解指定了正确的包路径,以便 Spring 容器能够找到并注册所有标记为@Component
的类。- 如果没有指定路径,默认会扫描主类所在的包及其子包。
Bean 名称:
- 默认情况下,Spring 容器会根据类名生成 Bean 的名称,首字母小写。例如,
MyService
类的 Bean 名称为myService
。- 也可以通过
@Component("customName")
显式指定 Bean 的名称。依赖注入:
- 通过
@Autowired
注解可以将 Spring 管理的 Bean 注入到其他 Bean 中。- 示例:
@Component public class AnotherService { @Autowired private MyService myService; public void performAction() { myService.doSomething(); } }
通过使用
@Component
注解,你可以方便地将普通 Java 类转换为 Spring 管理的 Bean,从而充分利用 Spring 框架提供的依赖注入、生命周期管理和事务管理等功能。
@Autowired是干什么的
@Autowired
是 Spring 框架中的一个注解,用于自动装配(自动注入)依赖关系。它可以让 Spring 容器自动将所需的依赖对象注入到目标 Bean 中,从而减少手动设置依赖的工作量,提高代码的可读性和可维护性。主要用途
自动装配依赖:
@Autowired
注解可以标注在类的成员变量、方法或构造函数上,指示 Spring 容器自动查找并注入匹配的依赖对象。- 如果没有匹配的 Bean,Spring 容器会抛出异常。
减少配置:
- 使用
@Autowired
可以减少 XML 配置文件中的<property>
和<constructor-arg>
标签,使配置更加简洁。常见用法
1. 成员变量注入
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class UserService { @Autowired private UserRepository userRepository; public void addUser(User user) { userRepository.save(user); } }
2. 构造函数注入
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class UserService { private final UserRepository userRepository; @Autowired public UserService(UserRepository userRepository) { this.userRepository = userRepository; } public void addUser(User user) { userRepository.save(user); } }
3. Setter 方法注入
import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class UserService { private UserRepository userRepository; @Autowired public void setUserRepository(UserRepository userRepository) { this.userRepository = userRepository; } public void addUser(User user) { userRepository.save(user); } }
高级用法
1. 按类型装配
@Autowired
默认按类型(byType)装配依赖对象。如果容器中有多个相同类型的 Bean,Spring 会抛出异常。import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class UserService { @Autowired private UserRepository userRepository; // 如果有多个 UserRepository 实现,Spring 会抛出异常 }
2. 按名称装配
如果需要按名称(byName)装配依赖对象,可以结合
@Qualifier
注解使用。import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Qualifier; import org.springframework.stereotype.Component; @Component public class UserService { @Autowired @Qualifier("userRepositoryImpl1") private UserRepository userRepository; public void addUser(User user) { userRepository.save(user); } }
3. 可选注入
如果某个依赖对象是可选的,可以使用
@Autowired(required = false)
注解。import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Component; @Component public class UserService { @Autowired(required = false) private UserRepository userRepository; public void addUser(User user) { if (userRepository != null) { userRepository.save(user); } } }
注意事项
依赖对象存在性:
- 确保被注入的依赖对象已经在 Spring 容器中注册。可以通过
@Component
、@Service
、@Repository
、@Controller
等注解或 XML 配置来注册 Bean。循环依赖:
- 避免在构造函数注入中出现循环依赖。Spring 容器会尝试解决循环依赖问题,但在某些情况下可能会失败。
类型冲突:
- 如果容器中有多个相同类型的 Bean,可以使用
@Qualifier
注解来指定具体的 Bean。构造函数注入 vs. 字段注入:
- 构造函数注入提供了更好的不可变性和清晰的依赖关系,推荐在可能的情况下使用构造函数注入。
- 字段注入虽然简洁,但不利于单元测试和代码的可读性。
通过使用
@Autowired
注解,你可以更方便地管理依赖关系,使代码更加简洁、易读和可维护。
IOC控制反转详解
指的就是将对象的控制权交给IOC容器,由IOC容器来创建及管理这些对象,IOC容器当中的这些对象也称为bean对象
component注解使用时间:
在项目开发当中,某一个类不能归到这三层里面,还想将这个类交给IOC容器管理,就可以使用component注解,最典型的就是一些工具类,其他推荐使用那三个衍生的
没有用value属性指明bean的名字的话,默认名字是类名首字母小写
@Repository("daoA"),一般直接采用默认值就好
直接都丢一个包下,省嘚配置环境
@Repository注解以后很少用,后面学习了mybatis框架之后,会通过另外一个注解来替代
DI依赖注入详解
指的是IOC容器要为应用程序提供运行时所依赖的资源
历时了不知道多久大概一个月吧 太慢了赶紧赶赶进度了