深圳网站制作哪家好,如何做淘宝客有没有免费的网站,工程平台公司做什么的,门户网站建设公司咨询1. Spring简介
1.1 Spring 核心设计思想
1.1.1 Spring 是什么#xff1f; Spring 是包含了众多⼯具⽅法的 IoC 容器。Spring 指的是 Spring Framework#xff08;Spring 框架#xff09;#xff0c;它是⼀个开源框架#xff0c;Spring ⽀持⼴泛的应⽤场景#xff0c;它…1. Spring简介
1.1 Spring 核心设计思想
1.1.1 Spring 是什么 Spring 是包含了众多⼯具⽅法的 IoC 容器。Spring 指的是 Spring FrameworkSpring 框架它是⼀个开源框架Spring ⽀持⼴泛的应⽤场景它可以让 Java 企业级的应⽤程序开发起来更简单。 1.1.1.1 什么是IoC容器 容器是⽤来容纳某种物品的装置。IoC Inversion of Control 翻译成中⽂是“控制反转”的意思控制权发⽣的反转不再是上级对象创建并控制下级对象了⽽是下级对象把注⼊将当前对象中下级的控制权不再由上级类控制了这样即使下级类发⽣任何改变当前类都是不受影响的这就是 IoC 的实现思想。Spring具备两个核心功能将对象存⼊到容器从容器中取出对象。对象的创建和销毁的权利都交给 Spring 来管理了它本身⼜具备了存储对象和获取对象的能⼒。 1.1.1.2 DI 概念说明 DI 是 Dependency Injection 的缩写翻译成中⽂是“依赖注⼊”的意思。依赖注⼊就是由 IoC 容器在运⾏期间动态地将某种依赖关系注⼊到对象之中。所以依赖注⼊DI和控制反转IoC是从不同的⻆度的描述的同⼀件事情就是指通过引⼊ IoC 容器利⽤依赖关系注⼊的⽅式实现对象之间的解耦IoC 是“⽬标”也是⼀种思想⽽⽬标和思想只是⼀种指导原则最终还是要有可⾏的落地⽅案⽽ DI就属于具体的实现。 1.1.1.3 IoC容器和普通程序开发的区别 将对象存储在 IoC 容器相当于将以后可能⽤的所有⼯具制作好都放到仓库中需要的时候直接取就⾏了⽤完再把它放回到仓库。new 对象的⽅式相当于每次需要工具了才现做用完扔掉了也不会保存下次再用的时候还得重新做。 1.2 Spring 创建和使用 1.2.1 创建 Spring 项目 使⽤ Maven ⽅式来创建⼀个 Spring 项⽬创建 Spring 项⽬和 Servlet 类似。 创建⼀个 Maven 项⽬ 然后跳转到了这个页面 添加 Spring 框架⽀持 在项⽬的 pom.xml 中添加 Spring 框架的⽀持spring-context(spring 上下⽂)和spring-beans(管理对 象的模块),xml 配置如下
dependenciesdependency groupIdorg.springframework/groupId artifactIdspring-context/artifactId version5.2.3.RELEASE/version /dependencydependency groupIdorg.springframework/groupId artifactIdspring-beans/artifactId version5.2.3.RELEASE/version /dependency
/dependencies添加启动类 最后在创建好的项⽬ java ⽂件夹下创建⼀个启动类包含 main ⽅法即可
public class App {public static void main(String[] args) {}
}到此为止一个spring项目就搭建好了。
1.2.2 存储 Bean 对象 Bean 就是 Java 语⾔中的⼀个普通对象,例如 public class User {public String sayHi(String name) { return name hello!;}
}创建 Bean
public class User {public String sayHi(String name) { return name hello!;}
}将 Bean 注册到容器 1在创建好的项⽬中添加 Spring 配置⽂件 spring-config.xml将此⽂件放到 resources 的根⽬录下 如下图所示 2 spring-config.xml 配置⽂件的固定格式为以下内容复制粘贴即可
?xml version1.0 encodingUTF-8?
beans xmlnshttp://www.springframework.org/schema/beans xmlns:xsihttp://www.w3.org/2001/XMLSchema-instance xsi:schemaLocationhttp://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd/beans3 将 User 对象注册到 Spring 中就可以在 标签中添加配置 格式如下
beansbean iduser classcom.bit.User/bean
/beans1.2.3 获取 Bean 对象
创建 Spring 上下⽂对象 1使⽤ ApplicationContext ApplicationContext context new ClassPathXmlApplicationContext(spring-con fig.xml);
2使⽤ BeanFactory BeanFactory beanFactory new XmlBeanFactory(new ClassPathResource(spring-config.xml)); ApplicationContext VS BeanFactory 继承关系和功能⽅⾯Spring 容器有两个顶级的接⼝BeanFactory 和 ApplicationContext。其中 BeanFactory 提供了基础的访问容器的能⼒⽽ ApplicationContext 属于 BeanFactory 的⼦类它除了继承了 BeanFactory 的所有功能之外它还拥有独特的特性 还添加了对国际化⽀持、资源访问⽀持、以及事件传播等⽅⾯的⽀持。性能⽅⾯ApplicationContext 是⼀次性加载并初始化所有的 Bean 对象⽽ BeanFactory 是需要那个才去加载那个因此更加轻量。 3使用ClassPathXmlApplicationContext ClassPathXmlApplicationContext 属于 ApplicationContext 的⼦类拥有 ApplicationContext 的所有功能通过 xml 的配置来获取所有的 Bean 容器。 获取指定的 Bean 对象
// 1.得到 Spring 上下⽂对象
ApplicationContext context new ClassPathXmlApplicationContext(spring-con fig.xml);
// 2.加载某个 bean
User user (User) context.getBean(user);Bean 的 Id 要⼀⼀对应如下图所示 getBean ⽅法的更多⽤法 根据类型获取 Bean UserController user context.getBean(UserController.class);名称 类型获取 Bean UserController user context.getBean(user, UserController.class);当有⼀个类型被重复注册到 spring-config.xml 中时只能使⽤根据名称获取了⽐如以 下场景就会导致程序报错 1.2.4 使用 Bean
public class App {public static void main(String[] args) {// 1.得到 Spring 上下⽂对象ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml); // 2.加载某个 beanUser user (User) context.getBean(user);// 3.调⽤相应的⽅法System.out.println(user.sayHi(Java));}
}1.2.4 使用注解读取和存储对象
配置扫描路径 配置⼀下存储对象的扫描包路径只有在被配置的包下且添加了注解的类才能被正确的识别并保存到 Spring 中。 在 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-packagecom.bit.service/content:component-scan/beans添加注解存储 Bean 对象 将对象存储在 Spring 中有两种注解类型可以实现
类注解Controller(表示业务逻辑层)、Service(服务层)、Repository(持久层)、Component、Configuration(配置层)。⽅法注解Bean 类注解是添加到某个类上的⽅法注解是放到某个⽅法上的。 Bean 命名规则 通常 bean 使⽤的都是标准的⼤驼峰命名读取的时候⾸字⺟⼩写 当⾸字⺟和第⼆个字⺟都是⼤写时不能正常读取到 bean Spring中 bean 存储时⽣成的命名规则 1 在 Idea 中使⽤搜索关键字“beanName”可以看到以下内容 它使⽤的是 JDK Introspector 中的 decapitalize ⽅法源码如下 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);
}所以对于上⾯报错的代码只要改为以下代码就可以正常运⾏了 类注解使用示例 Controller控制器存储 使⽤ Controller 存储 bean Controller // 将对象存储到 Spring 中
public class UserController {public void sayHi(String name) {System.out.println(Hi, name);}
}先使⽤之前读取对象的⽅式读取上⾯的 UserController 对象 public class Application {public static void main(String[] args) {// 1.得到 spring 上下⽂ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);// 2.得到 beanUserController userController (UserController) context.getBean(userController);// 3.调⽤ bean ⽅法userController.sayHi(Bit);}
}Service服务存储 使⽤ Service 存储 bean Service
public class UserService {public void sayHi(String name) {System.out.println(Hi, name);}
}读取 bean class App {public static void main(String[] args) {// 1.得到 spring 上下⽂ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);// 2.得到 beanUserService userService (UserService) context.getBean(userService);// 3.调⽤ bean ⽅法userService.sayHi(Bit);}
}Repository仓库存储 使⽤ Repository 存储 bean Repository
public class UserRepository {public void sayHi(String name) {System.out.println(Hi, name);}
}读取 bean class App {public static void main(String[] args) {// 1.得到 spring 上下⽂ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);// 2.得到某个 beanUserRepository userRepository (UserRepository) context.getBean(userRepository);// 3.调⽤ bean ⽅法userRepository.sayHi(Bit);}
}Component组件存储 使⽤ Component 存储 bean Component
public class UserComponent {public void sayHi(String name) {System.out.println(Hi, name);}
}读取 bean class App {public static void main(String[] args) {// 1.得到 spring 上下⽂ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);// 2.得到某个 beanUserComponent userComponent (UserComponent) context.getBean(userComponent);// 3.调⽤ bean ⽅法userComponent.sayHi(Bit);}
}Configuration配置存储 Configuration
public class UserConfiguration {public void sayHi(String name) {System.out.println(Hi, name);}
}读取 bean class App {public static void main(String[] args) {// 1.得到 spring 上下⽂ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);// 2.得到某个 beanUserConfiguration userConfiguration (UserConfiguration) context.getBean(userConfiguration);// 3.调⽤ bean ⽅法userConfiguration.sayHi(Bit);}
}为什么有这么多功能一样的注解 它们的功能都是一样的让程序员看到类注解之后就能直接了解当前类的⽤途。 程序的⼯程分层调⽤流程 查看 Controller / Service / Repository / Configuration 等注解的源码发现这些注解⾥⾯都有⼀个注解 Component说明它们本身就是属于 Component 的“⼦类”。 ⽅法注解Bean 使用示例 ⽅法注解要配合类注解使⽤ 在 Spring 框架的设计中⽅法注解 Bean 要配合类注解才能将对象正常的存储到 Spring 容器中 使用Bean存储 bean
Component
public class Users {Beanpublic User user1() { User user new User(); user.setId(1); user.setName(Java); return user;}
}读取bean public class Application {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml); User user (User) context.getBean(user1); System.out.println(user.toString());}
}重命名 Bean 可以通过设置 name 属性给 Bean 对象进⾏重命名。重 Component
public class Users { Bean(name {u1}) public User user1() { User user new User(); user.setId(1); user.setName(Java); return user;}
}命名的 name 其实是⼀个数组⼀个 bean 可以有多个名字。 Bean(name {u1, us1}) public User user1() { User user new User(); user.setId(1); user.setName(Java); return user;
}name{} 可以省略 Bean({u1, us1})
public User user1() { User user new User(); user.setId(1); user.setName(Java); return user;
}此时使⽤ u1/us1 就可以获取到 User 对象了 class App {public static void main(String[] args) {// 1.得到 spring 上下⽂ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml); // 2.得到某个 beanUser user (User) context.getBean(u1);// 3.调⽤ bean ⽅法System.out.println(user);}
}对象装配 获取 bean 对象也叫做对象装配是把对象取出来放到某个类中有时候也叫对象注⼊。 1 属性注⼊ 属性注⼊使⽤ Autowired 实现。 属性注⼊的优点是简洁使⽤⽅便缺点是只能⽤于 IoC 容器如果是⾮ IoC 容器不可⽤并且只 有在使⽤的时候才会出现 NPE空指针异常。 示例 Service 类的实现代码如下 import org.springframework.stereotype.Service;Service
public class UserService {/*** 根据 ID 获取⽤户数据** param id* return*/public User getUser(Integer id) { // 伪代码不连接数据库 User user new User(); user.setId(id); user.setName(Java- id); return user;}
}Controller 类的实现代码如下 import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Controller;Controller
public class UserController {// 注⼊⽅法1属性注⼊ Autowiredprivate UserService userService;public User getUser(Integer id) { return userService.getUser(id); }
}核⼼实现 获取 Controller 中的 getUser ⽅法 import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;public class UserControllerTest {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml); UserController userController context.getBean(UserController.cla ss);System.out.println(userController.getUser(1).toString());}
}运行结果 2构造⽅法注⼊ 构造⽅法注⼊是在类的构造⽅法中实现注⼊。 构造⽅法注⼊是 Spring 推荐的注⼊⽅式它的缺点是如果有多个注⼊会显得⽐较臃肿但出现这 种情况应该考虑⼀下当前类是否符合程序的单⼀职责的设计模式优点是通⽤性在使⽤之前⼀定能把保证注⼊的类不为空。 示例 Controller
public class UserController2 {// 注⼊⽅法2构造⽅法注⼊ private UserService userService; // 创建userService引用Autowired public UserController2(UserService userService) { // 注入并通过构造方法让上面的引用指向注入进来的这个对象this.userService userService;}public User getUser(Integer id) { return userService.getUser(id); }
}1 如果只有⼀个构造⽅法那么 Autowired 注解可以省略 2如果类中有多个构造⽅法那么需要添加上 Autowired 来明确指定到底使⽤哪个构造⽅法否则 程序会报错 3 Setter 注⼊ Setter 注⼊和 构造方法注入 实现类似只不过在设置 set ⽅法的时候需要加上 Autowired 注解。 Setter ⽅式是 Spring 前期版本推荐的注⼊⽅式但通⽤性不如构造⽅法所有 Spring 现版本已 经推荐使⽤构造⽅法注⼊的⽅式来进⾏类注⼊了。 示例 Controller
public class UserController3 {// 注⼊⽅法3Setter注⼊ private UserService userService;Autowiredpublic void setUserService(UserService userService) { this.userService userService;}public User getUser(Integer id) { return userService.getUser(id); }
} 4 Resource注入 Autowired 和 Resource 的区别 Autowired 来⾃于 Spring⽽ Resource 来⾃于 JDK 的注解相⽐于 Autowired Resource ⽀持更多的参数设置例如 name 设置根据名称获取 Bean。Autowired 可⽤于 Setter 注⼊、构造方法注⼊和 属性注⼊。⽽ Resource 只能⽤于 Setter 注⼊和 属性注⼊ 不能⽤于构造函数注⼊。 5使用同⼀类型多个 Bean 报错处理当出现以下多个 Bean返回同⼀对象类型时程序会报错。 示例 Component
public class Users {// 第一个beanBeanpublic User user1() { User user new User(); user.setId(1); user.setName(Java); return user;}// 第二个beanBeanpublic User user2() { User user new User(); user.setId(2); user.setName(MySQL); return user;}
}在另⼀个类中获取 User 对象 Controller
public class UserController4 {// 注⼊ Resource private User user;public User getUser() { return user;}
}执⾏结果 解决方法 1使⽤ Resource(name“XXX”)来指定bean Controller
class UserController4 { // 注⼊Resource(name user1) private User user;public User getUser() { return user;}
}2 使⽤ Qualifier来指定bean Controller
public class UserController5 { // 注⼊Autowired Qualifier(value user2) private User user;public User getUser() { return user;}
}2. Bean 详解
2.1 Bean的作用域 限定程序中变量的可⽤范围叫做作⽤域或者说在源代码中定义变量的某个区域就叫做作⽤域。 Bean 的作⽤域是指 Bean 在 Spring 整个框架中的某种⾏为模式。 Bean 有 6 种作⽤域singleton(单例作⽤域)prototype(原型作⽤域/多例作⽤域) request(请求作⽤域)session(回话作⽤域)application(全局作⽤域)websocket(HTTP WebSocket 作⽤域)。后 4 种状态是 Spring MVC 中的值在普通的 Spring 项⽬中只有前两种。 2.1.1 singleton Spring默认选择该作⽤域该作⽤域下的Bean在IoC容器中只存在⼀个实例获取Bean即通过applicationContext.getBean等⽅法获取及装配Bean即通过Autowired等注⼊都是同⼀个对象。通常⽆状态的BeanBean对象的属性状态不需要更新使⽤该作⽤域单例可以很⼤程度上提⾼性能。 示例 公共bean Component
public class Users {Beanpublic User user1() {User user new User();user.setId(1);user.setName(Java); // 【重点名称是 Java】return user;}
}A ⽤户使⽤时进⾏了修改操作
Controller
public class BeanScopesController {Autowiredprivate User user1;public User getUser1() {User user user1;System.out.println(Bean 原 Name user.getName());user.setName(悟空); // 【重点进⾏了修改操作】return user;}
}B ⽤户再去使⽤公共 Bean
Controller
public class BeanScopesController2 {Autowiredprivate User user1;public User getUser1() {User user user1;return user;}
}查看 A ⽤户和 B ⽤户公共 Bean 的值
public class BeanScopesTest {public static void main(String[] args) {ApplicationContext context new ClassPathXmlApplicationContext(spring-config.xml);BeanScopesController beanScopesController context.getBean(BeanScopesController.class);System.out.println(A 对象修改之后 Name beanScopesController.getUser1().toString());BeanScopesController2 beanScopesController2 context.getBean(BeanScopesController2.class);System.out.println(B 对象读取到的 Name beanScopesController2.getUser1().toString());}
}执⾏结果
2.1.2 prototype 每次对该作⽤域下的Bean的请求都会创建新的实例获取Bean即通过applicationContext.getBean等⽅法获取及装配Bean即通过Autowired注⼊都是新的对象实例。通常有状态Bean对象的属性状态需要更新的Bean使⽤该作⽤域。 2.1.3 request 每次http请求会创建新的Bean实例类似于prototype。用于⼀次http的请求和响应的共享Bean限定SpringMVC中使⽤。 2.1.4 session 在⼀个http session中定义⼀个Bean实例用于用户回话的共享Bean⽐如记录⼀个⽤户的登陆信息。限定SpringMVC中使⽤。 2.1.5 application 在⼀个http servlet Context中定义⼀个Bean实例用于Web应⽤的上下⽂信息⽐如记录⼀个应⽤的共享信息。限定SpringMVC中使⽤。 application 是 Spring Web 中的作⽤域作⽤于 Servlet 容器。singleton 是 Spring Core 的作⽤域singleton 作⽤于 IoC 的容器。 2.1.6 websocket 在⼀个HTTP WebSocket的⽣命周期中定义⼀个Bean实例用于WebSocket的每次会话中保存了⼀个Map结构的头信息将⽤来包裹客户端消息头。第⼀次初始化后直到WebSocket结束都是同⼀个Bean。限定Spring WebSocket中使⽤。 2.2 设置Bean的作用域 使⽤ Scope 标签就可以⽤来声明 Bean 的作⽤域。 1 直接设置值Scope(“prototype”) 2 使⽤枚举设置Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE) 示例
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
Component
public class Users {Scope(ConfigurableBeanFactory.SCOPE_PROTOTYPE)Bean(name u1)public User user1() {User user new User();user.setId(1);user.setName(Java); // 【重点名称是 Java】return user;}
}2.2 Bean的生命周期
2.2.1 Spring 执行流程 2.2.2 Bean 的执行流程 启动 Spring 容器 -- 实例化 Bean(分配内存空间,从⽆到有) -- Bean注册到Spring中(存操作) -- 将Bean装配到需要的类中(取操作)。 2.2.3 Bean的生命周期 ⽣命周期指的是⼀个对象从诞⽣到销毁的整个⽣命过程我们把这个过程就叫做⼀个对象的⽣命周期。 实例化 Bean为 Bean 分配内存空间设置属性Bean 注⼊和装配Bean 初始化 3.1 实现了各种 Aware 通知的⽅法如 BeanNameAware、BeanFactoryAware ApplicationContextAware 的接⼝⽅法 3.2 执⾏ BeanPostProcessor 初始化前置⽅法 3.3 执⾏ PostConstruct 初始化⽅法依赖注⼊操作之后被执⾏ 3.4 执⾏⾃⼰指定的 init-method ⽅法如果有指定的话 3.5 执⾏ BeanPostProcessor 初始化后置⽅法。使⽤ Bean销毁 Bean。执行销毁容器的各种⽅法如 PreDestroy、DisposableBean 接⼝⽅法、destroy-method。 实例化和初始化的区别 实例化和属性设置是 Java 级别的系统“事件”其操作过程不可⼈⼯⼲预和修改⽽初始化是给开发者 提供的可以在实例化之后类加载完成之前进⾏⾃定义“事件”处理。 如何理解Bean生命周期 Bean 的⽣命流程看似繁琐但咱们可以以⽣活中的场景来理解它⽐如我们现在需要买⼀栋房⼦那么我们的流程是这样的 先买房实例化从⽆到有装修设置属性买家电如洗⾐机、冰箱、电视、空调等[各种]初始化⼊住使⽤ Bean卖出去Bean 销毁。