怎样建设那种游戏网站,江西网站建设费用,wordpress建站准备,深圳品牌馆设计公司到了学习 JavaEE 这块要有一个思想,实现一个功能的时候,先考虑下有没有实现对应功能的注解.
在 Spring 中想要更简单的存储和读取对象的核心是使用注解#xff0c;也就是我们接下来要学习 Spring 中的相关注解#xff0c;来存储和读取 Bean 对象
1.存储 Bean 对象
之前我们…到了学习 JavaEE 这块要有一个思想,实现一个功能的时候,先考虑下有没有实现对应功能的注解.
在 Spring 中想要更简单的存储和读取对象的核心是使用注解也就是我们接下来要学习 Spring 中的相关注解来存储和读取 Bean 对象
1.存储 Bean 对象
之前我们存储 Bean 时需要在 spring-config 中添加一行 bean 注册内容才行如下图所示
而现在我们只需要一个注解就可以替代之前要写一行配置的要求
1.前置工作
在 spring-config.xml 添加如下配置
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beansxmlns:xsihttp://www.w3.org/2001/XMLSchema-instancexmlns:contenthttp://www.springframework.org/schema/contextxsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsdcontent:component-scan base-package/content:component-scan
/beans
base-package 写自己的内容 2.添加注解存储 Bean 对象
想要将对象存储在 Spring 中有两种注解类型可以实现 类注解Controller、Service、Repository、Component、Configuration 方法注解Bean
1.Controller(控制器)
校验参数的合法性(类似于安检系统)
package com.wjh.demo;import org.springframework.stereotype.Controller;/*** projectName: test-2023-11-22* package: com.wjh.demo* className: User* author: 王嘉辉* description:* date: 2023/11/22 19:16* version: 1.0*/
Controller(userinfo)
public class User {public void sayHello() {System.out.println(Hi,User!);}
}
import com.wjh.demo.User;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** projectName: test-2023-11-22* package: PACKAGE_NAME* className: App* author: 王嘉辉* description:* date: 2023/11/22 19:16* version: 1.0*/
public class App {public static void main(String[] args) {//1.得到容器对象ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);//2.得到 Bean 对象User user context.getBean(userinfo,User.class);//3.使用 Bean 对象user.sayHello();}
} 2.Service(服务)
业务组装(相当于客服中心)
不做业务功能的实现
Service
public class User {public void sayHello() {System.out.println(Hi,User!);}
}3.Repository(数据持久层)
实际的业务处理(实际办理的业务)
Repository
public class User {public void sayHello() {System.out.println(Hi,User!);}
}4.Component(组件)
工具类层(基础的工具)
Component
public class User {public void sayHello() {System.out.println(Hi,User!);}
}5.Configuration(配置)
配置层(配置)
Configuration
public class User {public void sayHello() {System.out.println(Hi,User!);}
}3.类注解存储 Bean 命名问题 默认类名首字母小写,就能获取到 Bean 对象 获取不到 Bean 对象 使用原类名,可以获取到 Bean 对象
我们可以在 Idea 中使用搜索关键字“beanName”
顺藤摸瓜我们最后找到了 bean 对象的命名规则的方法 public static String decapitalize(String name) {if (name null || name.length() 0) {return name;}// 如果第⼀个字⺟和第⼆个字⺟都为⼤写的情况是把 bean 的⾸字⺟也⼤写存储了if (name.length() 1 Character.isUpperCase(name.charAt(1)) Character.isUpperCase(name.charAt(0))){return name;}// 否则就将⾸字⺟⼩写char chars[] name.toCharArray();chars[0] Character.toLowerCase(chars[0]);return new String(chars);
}4. 为什么要这么多类注解
为什么需要这么多的类注解也是相同的原因就是让程序员看到类注解之后就能直接了解当前类的用途比如 Controller表示的是业务逻辑层 Servie服务层 Repository持久层 Configuration配置层。
程序的工程分层调用流程如下: 查看 Controller / Service / Repository / Configuration 等注解的源码发现 其实这些注解里面都有一个注解 Component说明它们本身就是属于Component 的“子类”。
5.方法注解 Bean
注意事项: 在使用 Bean 注解 的时候,必须要配合五大类注解一起使用 Bean 获取时 Bean 默认命名 方法名
package com.wjh.demo.model;/*** projectName: test-2023-11-23* package: com.wjh.demo.service.model* className: ArticleInfo* author: 王嘉辉* description:* date: 2023/11/23 19:28* version: 1.0*/import java.time.LocalDateTime;/***普通的文章实体类*/public class ArticleInfo {private int aid;private String title;private String content;private LocalDateTime createTime;public int getAid() {return aid;}public void setAid(int aid) {this.aid aid;}public String getTitle() {return title;}public void setTitle(String title) {this.title title;}public String getContent() {return content;}public void setContent(String content) {this.content content;}public LocalDateTime getCreateTime() {return createTime;}public void setCreateTime(LocalDateTime createTime) {this.createTime createTime;}Overridepublic String toString() {return ArticleInfo{ aid aid , title title \ , content content \ , createTime createTime };}
}
package com.wjh.demo.service;import com.wjh.demo.model.ArticleInfo;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;/*** projectName: test-2023-11-23* package: com.wjh.demo.service* className: Articles* author: 王嘉辉* description:* date: 2023/11/23 19:33* version: 1.0*/
Component
public class Articles {Bean //将当前方法返回的对象存储到 IoC 容器public ArticleInfo articleInfo() {//伪代码ArticleInfo articleInfo new ArticleInfo();articleInfo.setAid(1);articleInfo.setTitle(今天周几?);articleInfo.setContent(今天周四!!);articleInfo.setCreateTime(LocalDateTime.now());return articleInfo;}
}import com.wjh.demo.model.ArticleInfo;
import com.wjh.demo.service.UConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** projectName: test-2023-11-23* package: PACKAGE_NAME* className: App* author: 王嘉辉* description:* date: 2023/11/22 19:16* version: 1.0*/
public class App {public static void main(String[] args) {//1.得到容器对象ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);//2.得到 Bean 对象//User user context.getBean(user,User.class);//UserService userService context.getBean(userService,UserService.class);//Teacher teacher context.getBean(teacher,Teacher.class);//UConfig uConfig context.getBean(UConfig,UConfig.class);ArticleInfo articleInfo context.getBean(articleInfo,ArticleInfo.class);//3.使用 Bean 对象//user.sayHello();// userService.sayHi();//teacher.sayHi();//uConfig.sayHi();System.out.println(articleInfo.toString());}
} 6.重命名 Bean 的几种方式
方式一: package com.wjh.demo.service;import com.wjh.demo.model.ArticleInfo;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;/*** projectName: test-2023-11-23* package: com.wjh.demo.service* className: Articles* author: 王嘉辉* description:* date: 2023/11/23 19:33* version: 1.0*/
Component
public class Articles {Bean(aaa) //将当前方法返回的对象存储到 IoC 容器public ArticleInfo articleInfo() {//伪代码ArticleInfo articleInfo new ArticleInfo();articleInfo.setAid(1);articleInfo.setTitle(今天周几?);articleInfo.setContent(今天周四!!);articleInfo.setCreateTime(LocalDateTime.now());return articleInfo;}
}import com.wjh.demo.model.ArticleInfo;
import com.wjh.demo.service.UConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** projectName: test-2023-11-23* package: PACKAGE_NAME* className: App* author: 王嘉辉* description:* date: 2023/11/22 19:16* version: 1.0*/
public class App {public static void main(String[] args) {//1.得到容器对象ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);//2.得到 Bean 对象//User user context.getBean(user,User.class);//UserService userService context.getBean(userService,UserService.class);//Teacher teacher context.getBean(teacher,Teacher.class);//UConfig uConfig context.getBean(UConfig,UConfig.class);ArticleInfo articleInfo context.getBean(aaa,ArticleInfo.class);//3.使用 Bean 对象//user.sayHello();// userService.sayHi();//teacher.sayHi();//uConfig.sayHi();System.out.println(articleInfo.toString());}
}
方式二: package com.wjh.demo.service;import com.wjh.demo.model.ArticleInfo;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;/*** projectName: test-2023-11-23* package: com.wjh.demo.service* className: Articles* author: 王嘉辉* description:* date: 2023/11/23 19:33* version: 1.0*/
Component
public class Articles {Bean(name bbb) //将当前方法返回的对象存储到 IoC 容器public ArticleInfo articleInfo() {//伪代码ArticleInfo articleInfo new ArticleInfo();articleInfo.setAid(1);articleInfo.setTitle(今天周几?);articleInfo.setContent(今天周四!!);articleInfo.setCreateTime(LocalDateTime.now());return articleInfo;}
}import com.wjh.demo.model.ArticleInfo;
import com.wjh.demo.service.UConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** projectName: test-2023-11-23* package: PACKAGE_NAME* className: App* author: 王嘉辉* description:* date: 2023/11/22 19:16* version: 1.0*/
public class App {public static void main(String[] args) {//1.得到容器对象ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);//2.得到 Bean 对象//User user context.getBean(user,User.class);//UserService userService context.getBean(userService,UserService.class);//Teacher teacher context.getBean(teacher,Teacher.class);//UConfig uConfig context.getBean(UConfig,UConfig.class);ArticleInfo articleInfo context.getBean(bbb,ArticleInfo.class);//3.使用 Bean 对象//user.sayHello();// userService.sayHi();//teacher.sayHi();//uConfig.sayHi();System.out.println(articleInfo.toString());}
}
方法三: package com.wjh.demo.service;import com.wjh.demo.model.ArticleInfo;
import org.springframework.context.annotation.Bean;
import org.springframework.stereotype.Component;import java.time.LocalDateTime;/*** projectName: test-2023-11-23* package: com.wjh.demo.service* className: Articles* author: 王嘉辉* description:* date: 2023/11/23 19:33* version: 1.0*/
Component
public class Articles {Bean(name {bbb,ccc}) //将当前方法返回的对象存储到 IoC 容器public ArticleInfo articleInfo() {//伪代码ArticleInfo articleInfo new ArticleInfo();articleInfo.setAid(1);articleInfo.setTitle(今天周几?);articleInfo.setContent(今天周四!!);articleInfo.setCreateTime(LocalDateTime.now());return articleInfo;}
}import com.wjh.demo.model.ArticleInfo;
import com.wjh.demo.service.UConfig;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;/*** projectName: test-2023-11-23* package: PACKAGE_NAME* className: App* author: 王嘉辉* description:* date: 2023/11/22 19:16* version: 1.0*/
public class App {public static void main(String[] args) {//1.得到容器对象ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);//2.得到 Bean 对象//User user context.getBean(user,User.class);//UserService userService context.getBean(userService,UserService.class);//Teacher teacher context.getBean(teacher,Teacher.class);//UConfig uConfig context.getBean(UConfig,UConfig.class);ArticleInfo articleInfo context.getBean(bbb,ArticleInfo.class);//3.使用 Bean 对象//user.sayHello();// userService.sayHi();//teacher.sayHi();//uConfig.sayHi();System.out.println(articleInfo.toString());}
}
当使用 Bean 重命名之后,此时在使用方法名获取 Bean 对象就不可行了 7.Bean 的注意事项
如果多个 Bean 使用相同的名称,那么程序执行不会报错,但是第一个 Bean 之后的对象不会被存放到容器中,也就是只有在第一次创建 Bean 的时候会将对象和 Bean 的名称关联起来,后续再有相同名称的 Bean 存储时,容器会自动忽略
2.获取 Bean 对象
获取 bean 对象也叫做对象装配是把对象取出来放到某个类中有时候也叫对象注入。
对象装配对象注入的实现方法以下 3 种
属性注入构造方法注入Setter 注入
1.属性注入 package com.java.demo.dao;import org.springframework.stereotype.Repository;/*** projectName: Demo* package: com.java.demo.dao* className: UserRepository* author: 王嘉辉* description:* date: 2023/11/23 21:38* version: 1.0*/
Repository
public class UserRepository {public int add() {System.out.println(Do UserRepository add method.);return 1;}
}
package com.java.demo.service;import com.java.demo.dao.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.stereotype.Service;/*** projectName: Demo* package: com.java.demo.service* className: UserService* author: 王嘉辉* description:* date: 2023/11/23 21:37* version: 1.0*/
Service
public class UserService {//1.属性注入Autowired //DI (依赖注入)private UserRepository userRepository;public int add() {System.out.println(Do UserService add method.);/*//传统写法UserRepository userRepository new UserRepository();return userRepository.add();*//*//Spring 1.0ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);UserRepository userRepository context.getBean(userRepository,UserRepository.class);return userRepository.add();*///Spring 2.0return userRepository.add();}
}
package com.java.demo.service;import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import javax.swing.*;import static org.junit.jupiter.api.Assertions.*;class UserServiceTest {org.junit.jupiter.api.Testvoid add() {ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);UserService userService context.getBean(userService, UserService.class);userService.add();}
}依赖注入 VS 依赖查找 依赖查找依赖 Bean 名称的Autowired 依赖注入流程:首先先根据 getType (从容器中) 获取对象,如果只获取到一个,那么直接将此对象注入到当前属性上,如果获取到多个对象,才会使用 getName(根据名称) 进行匹配. Component
public class Users {Beanpublic User user1() {User user new User();user.setId(1);user.setName(Java);return user;}Beanpublic User user2() {User user new User();user.setId(2);user.setName(MySQL);return user;}
}Controller
public class UserController4 {// 注⼊Resourceprivate User user;public User getUser() {return user;}
}同类型的 Bean 存储到容器多个,获取时报错:
解决方案:
1.将属性的名字和 Bean 的名字对应上
2.Autowired 配合 Qualifier 一起使用
Controller
public class UserController5 {// 注⼊AutowiredQualifier(value user2)private User user;public User getUser() {return user;}
}
使用属性注入的优缺点:
优点:简洁,使用简单
缺点:
1.无法注入 final 修饰的变量 被 final 修饰的变量需要直接赋值或构造方法中进行赋值 它不符合 Java 中 final 的使用规范所以就不能注入成功了
2.通用性问题:使用属性注入的方式只适用于 IoC 框架容器
3.设计原则问题更容易违背单一设计原则。
使用属性注入的方式因为使用起来很简单所以开发者很容易在一个类中同时注入多个对象而这些对象的注入是否有必要是否符合程序设计中的单一职责原则就变成了一个问题。 但可以肯定的是注入实现越简单那么滥用它的概率也越大所以出现违背单一职责原则的概率也越大。 注意这里强调的是违背设计原则单一职责的可能性而不是一定会违背设计原则二者有着本质的区别。
2. Setter 注入
Setter 注入和属性的 Setter 方法实现类似只不过在设置 set 方法的时候需要加上Autowired 注解
package com.java.demo.service;import com.java.demo.dao.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** projectName: test-2023-11-26* package: com.java.demo.service* className: UserService2* author: 王嘉辉* description:* date: 2023/11/26 19:52* version: 1.0*/
Service
public class UserService2 {private UserRepository userRepository;Autowiredpublic void setUserRepository(UserRepository userRepository) {this.userRepository userRepository;}public void sayHello() {System.out.println(Do UserService2 sayHello);userRepository.add();}
}
package com.java.demo.service;import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import static org.junit.jupiter.api.Assertions.*;class UserService2Test {Testvoid sayHello() {ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);UserService2 userService2 context.getBean(userService2, UserService2.class);userService2.sayHello();}
}Setter 注入的优缺点
优点:Setter 注入它完全符合单一职责的设计原则因为每一个 Setter 只针对一个对象
缺点:
1.无法注入 一个 final 修饰的变量 2.Setter 注入的对象可以被修改,Setter 本来就是一个方法,既然是方法,就有可被多次调用和修改. 3.构造方法注入
标准的属性注入的写法
package com.java.demo.service;import com.java.demo.dao.UserRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;/*** projectName: test-2023-11-26* package: com.java.demo.service* className: UserService3* author: 王嘉辉* description:* date: 2023/11/26 20:13* version: 1.0*/
Service
public class UserService3 {private UserRepository userRepository;Autowiredpublic UserService3(UserRepository userRepository) {this.userRepository userRepository;}public void sayHi() {System.out.println(Do UserService3 sayHi);userRepository.add();}
}
package com.java.demo.service;import org.junit.jupiter.api.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;import static org.junit.jupiter.api.Assertions.*;class UserService3Test {Testvoid sayHi() {ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);UserService3 userService3 context.getBean(userService3, UserService3.class);userService3.sayHi();}
}如果只有一个构造方法那么 Autowired 注解可以省略 但是如果类中有多个构造方法那么需要添加上 Autowired 来明确指定到底使用哪个构造方法 构造方法注入的优缺点:
优点:
1.可注入一个 final 修饰的变量 2.注入对象不会被修改
构造方法注入不会像 Setter 注入那样构造方法在对象创建时只会执行一次因此它不存在注入对象被随时调用修改的情况。
3.注入对象会被完全初始化
因为依赖对象是在构造方法中执行的而构造方法是在对象创建之初执行的因此被注入的对象在使用之前会被完全初始化这也是构造方法注入的优点之一。
4.通用性更好
构造方法和属性注入不同构造方法注入可适用于任何环境无论是 IoC 框架还是非 IoC 框架构造方法注入的代码都是通用的所以它的通用性更好。
缺点:
1.写法比属性注入复杂
2.使用构造方法注入,解决不了循环依赖的问题(Spring 的三级缓存解决)
4.Resource 另一种注入关键字
Controller
public class UserController {// 注⼊Resourceprivate UserService userService;public User getUser(Integer id) {return userService.getUser(id);}
}Autowired 和 Resource 的区别 出身不同Autowired 来自于 Spring而Resource 来自于 JDK 的注解 使用时设置的参数不同相比于 Autowired 来说Resource 支持更多的参数设置例如name 设置根据名称获取 Bean。 Autowired 可用于 Setter 注入、构造函数注入和属性注入而Resource 只能用于 Setter 注入和属性注入不能用于构造函数注入 使用Autowired 在IDEA 专业版可能会误报,Resource 不存在误报问题