Spring Boot常见企业开发场景应用、自动配置原理结构分析(三)

本文涉及的产品
云数据库 RDS MySQL,集群系列 2核4GB
推荐场景:
搭建个人博客
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
注册配置 MSE Nacos/ZooKeeper,118元/月
简介: Spring Boot常见企业开发场景应用、自动配置原理结构分析

Spring Boot常见企业开发场景应用、自动配置原理结构分析(二)https://developer.aliyun.com/article/1423060


  1. 这里导入了ActiveMQ的起步依赖
  2. 编写DAO
public interface UserRepository extends JpaRepository{
}
1. 编写Service
public interface UserService {
 /**
  * 根据ID获取用户
  * @param i
  * @return
  */
 User get(int id);
 /**
  * 查询所有用户
  * @return
  */
 List findAll();
 /**
  * 新增用户
  * @param user
  */
 void add(User user);
}
@Service
@Transactional
public class UserServiceImpl implements UserService{
 @Autowired
 private UserRepository userRepository;
 @Override
 public User get(int id) {
  return userRepository.findOne(id);
 }
 @Override
 public List findAll() {
  return userRepository.findAll();
 }
 @Override
 public void add(User user) {
  userRepository.save(user);
 }
}
1. 编写Controller
@Controller
@RequestMapping("/user")
public class UserController {
 @Autowired
 private UserService userService;
 @Autowired
 private JmsTemplate jmsTemplate;
 @RequestMapping("/findUserList")
 public String findUserList(Model model) {
  List list = userService.findAll();
  model.addAttribute("list", list);
  return "/index.jsp";
 }
 @RequestMapping("/add")
 public String add(User user) {
  userService.add(user);
  final List userList = userService.findAll();
  jmsTemplate.send("queue_page", new MessageCreator() {
   @Override
   public Message createMessage(Session session) throws JMSException {
    return session.createTextMessage(JSON.toJSONString(userList));
   }
  });
  return "redirect:/user/findUserList";
 }
}
1. 在添加一个用户,往AMQ中发送一条queue消息
2. 编写Listener
@Component
public class PageGeneratorListener {
 @Value("${freemarker.output_path}")
 private String OUTPUT_PATH;
 @Autowired
 private Configuration configuration;
 @JmsListener(destination="queue_page")
 public void genHtml(String userListStr) throws Exception {
  Template template = configuration.getTemplate("user_list.ftl");
  List userList = JSON.parseArray(userListStr, User.class);
  Map map = new HashMap();
  map.put("list", userList);
  template.process(map, new FileWriter(OUTPUT_PATH + "user_list.html"));
 }
}
1. 监听AMQ中queue_page队列的消息,如果接收到消息,使用FreeMarker重新生成一个HTML页面在服务器端
2. 编写入口
@SpringBootApplication
public class Application {
 public static void main(String[] args) {
  SpringApplication.run(Application.class);
 }
 @Bean(name="datasource")
 @Primary
 @ConfigurationProperties(prefix="c3p0")
 public ComboPooledDataSource c3p0DataSource() throws PropertyVetoException {
  ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
  return comboPooledDataSource;
 }
}
1. 编写配置文件
server.port=10086
server.context-path=/
freemarker.output_path=G:/workspace/free_test/t51/src/main/webapp/
spring.activemq.broker-url=tcp://localhost:61616
spring.activemq.user=admin
spring.activemq.password=admin
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql:///springboot
c3p0.user=root
c3p0.password=000000
  1. 构建基于Spring Security访问控制应用程序
  1. 导入依赖
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.5.14.RELEASE</version>
 </parent>
 <dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-data-jpa</artifactId>
  </dependency>
  <dependency>
   <groupId>mysql</groupId>
   <artifactId>mysql-connector-java</artifactId>
   <version>5.1.6</version>
  </dependency>
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
  </dependency>
  <dependency>
   <groupId>org.apache.tomcat.embed</groupId>
   <artifactId>tomcat-embed-jasper</artifactId>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-security</artifactId>
  </dependency>
  <dependency>
   <groupId>c3p0</groupId>
   <artifactId>c3p0</artifactId>
   <version>0.9.1</version>
  </dependency>
  <dependency>
   <groupId>org.apache.commons</groupId>
   <artifactId>commons-lang3</artifactId>
   <version>3.4</version>
  </dependency>
 </dependencies>
a. 导入了Spring Security的起步依赖spring-boot-starter-security
b. 编写DAO
public interface UserRepository extends JpaRepository<User, Integer>{
 // 根据用户名查询用户
 User findByUsername(String username);
}
  1. 编写Service
public interface UserService {
 /**
  * 根据ID获取用户
  * @param i
  * @return
  */
 User get(int id);
 /**
  * 查询所有用户
  * @return
  */
 List<User> findAll();
 /**
  * 新增用户
  * @param user
  */
 void add(User user);
}
@Service
@Transactional
public class UserServiceImpl implements UserService{
 @Autowired
 private UserRepository userRepository;
 @Override
 public User get(int id) {
  return userRepository.findOne(id);
 }
 @Override
 public List<User> findAll() {
  return userRepository.findAll();
 }
 @Override
 public void add(User user) {
  userRepository.save(user);
 }
}
  1. 编写Spring Security登录验证用户服务
@Service
@Transactional
public class AuthUserService implements UserDetailsService {
 @Autowired
 private UserRepository userRepository;
 @Override
 public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
  if(StringUtils.isNotBlank(username)) {
            // 从数据库中获取用户
   User user = userRepository.findByUsername(username);
   if(user != null) {
                // 创建用户、加载角色
    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    authorities.add(new SimpleGrantedAuthority("ROLE_USER"));
   return new org.springframework.security.core.userdetails.User(
    username, user.getPassword(), authorities);
   }
   else {
    throw new UsernameNotFoundException("用户名不存在");
   }
  }
  return null;
 }
}
  1. 编写Controller
@Controller
@RequestMapping("/user")
public class UserController {
 @Autowired
 private UserService userService;
 @RequestMapping("/findUserList")
 public String findUserList(Model model) {
  List<User> list = userService.findAll();
  model.addAttribute("list", list);
  return "/index.jsp";
 }
 @RequestMapping("/add")
 public String add(User user) {
  userService.add(user);
  return "redirect:/user/findUserList";
 }
}
  1. 编写应用入口
@SpringBootApplication
public class Application {
 public static void main(String[] args) {
  SpringApplication.run(Application.class);
 }
 @Bean(name="datasource")
 @Primary
 @ConfigurationProperties(prefix="c3p0")
 public ComboPooledDataSource c3p0DataSource() throws PropertyVetoException {
  ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
  return comboPooledDataSource;
 }
}
  1. 编写配置文件
server.port=10086
 server.context-path=/
 freemarker.output_path=G:/workspace/free_test/t51/src/main/webapp/
 c3p0.driverClass=com.mysql.jdbc.Driver
 c3p0.jdbcUrl=jdbc:mysql:///springboot
 c3p0.user=root
 c3p0.password=000000
  1. 编写页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <title>JSP测试</title>
 </head>
 <body>
 <table border="1">
 <form action="<%=request.getContextPath()%>/user/add" method="post">
 <tr>
 <td>用户名:<input type="text" name="username"/></td>
 <td>密码:<input type="text" name="password"/></td>
 <td><input type="submit" value="新增"/></td>
 </tr>
 </form>
 </table>
 <table border=1>
 <tr>
 <th>ID</th>
 <th>用户名</th>
 <th>密码</th>
 </tr>
 <c:forEach items="${list}" var="user">
 <tr>
 <td>${user.id}</td>
 <td>${user.username}</td>
 <td>${user.password}</td>
 </tr>
 </c:forEach>
 </table>
 </body>
 </html>
  1. 访问http://localhost:10086/user/findUserList,弹出登录对话框,输入数据库中任意的用户名和密码登录即可。

构建基于Dubbox分布式架构应用程序

启动ZooKeeper

编写服务提供者

  1. 导入依赖
<parent>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-parent</artifactId>
 <version>1.5.14.RELEASE</version>
 </parent>
 <dependencies>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-web</artifactId>
 </dependency>
 <dependency>
 <groupId>org.springframework.boot</groupId>
 <artifactId>spring-boot-starter-data-jpa</artifactId>
 </dependency>
 <dependency>
 <groupId>com.cjoop</groupId>
 <artifactId>spring-boot-starter-dubbox</artifactId>
 <version>0.0.1</version>
 </dependency>
 <dependency>
 <groupId>org.apache.zookeeper</groupId>
 <artifactId>zookeeper</artifactId>
 <version>3.4.7</version>
 </dependency>
 <dependency>
 <groupId>com.github.sgroschupf</groupId>
 <artifactId>zkclient</artifactId>
 <version>0.1</version>
 </dependency>
 <dependency>
 <groupId>mysql</groupId>
 <artifactId>mysql-connector-java</artifactId>
 <version>5.1.6</version>
 </dependency>
 <dependency>
 <groupId>javax.servlet</groupId>
 <artifactId>jstl</artifactId>
 </dependency>
 <dependency>
 <groupId>org.apache.tomcat.embed</groupId>
 <artifactId>tomcat-embed-jasper</artifactId>
 </dependency>
 <dependency>
 <groupId>c3p0</groupId>
 <artifactId>c3p0</artifactId>
 <version>0.9.1</version>
 </dependency>
 <dependency>
 <groupId>org.apache.commons</groupId>
 <artifactId>commons-lang3</artifactId>
 <version>3.4</version>
 </dependency>
 </dependencies>
  1. 这里导入了Dubbox的起步依赖,这样配置起来很方便。
  2. 导入实体类,注意因为要在网络上传输,所以要实现Serializable接口
@Entity
@Table(name="t_user")
public class User implements Serializable{
 @Id
 @GeneratedValue(strategy=GenerationType.IDENTITY)
 private Integer id;
 private String username;
 private String password;
 public User() {
 }
 public User(Integer id, String username, String password) {
  this.id = id;
  this.username = username;
  this.password = password;
 }
 public User(String username, String password) {
  this(null, username, password);
 }
 public Integer getId() {
  return id;
 }
 public void setId(Integer id) {
  this.id = id;
 }
 public String getUsername() {
  return username;
 }
 public void setUsername(String username) {
  this.username = username;
 }
 public String getPassword() {
  return password;
 }
 public void setPassword(String password) {
  this.password = password;
 }
 @Override
 public String toString() {
  return "User [id=" + id + ", username=" + username + ", password=" + password + "]";
 }
}
  1. 编写DAO
public interface UserRepository extends JpaRepository<User, Integer>{
 User findByUsername(String username);
}
  1. 编写Service(注意:请使用Dubbox中的@Service,否则服务将不会被发布)
public interface UserService {
 /**
  * 根据ID获取用户
  * @param i
  * @return
  */
 User get(int id);
 /**
  * 查询所有用户
  * @return
  */
 List<User> findAll();
 /**
  * 新增用户
  * @param user
  */
 void add(User user);
}
@Service
@Transactional
public class UserServiceImpl implements UserService{
 @Autowired
 private UserRepository userRepository;
 @Override
 public User get(int id) {
  return userRepository.findOne(id);
 }
 @Override
 public List<User> findAll() {
  return userRepository.findAll();
 }
 @Override
 public void add(User user) {
  userRepository.save(user);
 }
}
  1. 编写入口
@SpringBootApplication
public class Application {
 public static void main(String[] args) {
  SpringApplication.run(Application.class);
 }
 @Bean(name="datasource")
 @Primary
 @ConfigurationProperties(prefix="c3p0")
 public ComboPooledDataSource c3p0DataSource() throws PropertyVetoException {
  ComboPooledDataSource comboPooledDataSource = new ComboPooledDataSource();
  return comboPooledDataSource;
 }
}
  1. 编写配置文件
server.port=10086
server.context-path=/
#配置Dubbo包扫描,自动将带有Service注解的类发布为Dubbox服务
dubbo.annotation.package=com.itheima.springboot.service
dubbo.application.name=com.itheima.user.service
c3p0.driverClass=com.mysql.jdbc.Driver
c3p0.jdbcUrl=jdbc:mysql:///springboot
c3p0.user=root
c3p0.password=000000
  1. 启动应用,如果服务发布成功,可以在Dubbo Admin上看到已经发布的服务

编写服务消费者

  1. 导入依赖
<parent>
  <groupId>org.springframework.boot</groupId>
  <artifactId>spring-boot-starter-parent</artifactId>
  <version>1.5.14.RELEASE</version>
 </parent>
 <dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>
  <dependency>
   <groupId>javax.servlet</groupId>
   <artifactId>jstl</artifactId>
  </dependency>
  <dependency>
   <groupId>org.apache.tomcat.embed</groupId>
   <artifactId>tomcat-embed-jasper</artifactId>
  </dependency>
  <dependency>
   <groupId>com.cjoop</groupId>
   <artifactId>spring-boot-starter-dubbox</artifactId>
   <version>0.0.1</version>
  </dependency>
  <dependency>
   <groupId>org.apache.zookeeper</groupId>
   <artifactId>zookeeper</artifactId>
   <version>3.4.7</version>
  </dependency>
  <dependency>
   <groupId>com.github.sgroschupf</groupId>
   <artifactId>zkclient</artifactId>
   <version>0.1</version>
  </dependency>
  <dependency>
   <groupId>org.javassist</groupId>
   <artifactId>javassist</artifactId>
  </dependency>
 </dependencies>
  1. 引入实体类
public class User {
 private Integer id;
 private String username;
 private String password;
 public User() {
 }
 public User(Integer id, String username, String password) {
 this.id = id;
 this.username = username;
 this.password = password;
 }
 public User(String username, String password) {
 this(null, username, password);
 }
 public Integer getId() {
 return id;
 }
 public void setId(Integer id) {
 this.id = id;
 }
 public String getUsername() {
 return username;
 }
 public void setUsername(String username) {
 this.username = username;
 }
 public String getPassword() {
 return password;
 }
 public void setPassword(String password) {
 this.password = password;
 }
 @Override
 public String toString() {
 return "User [id=" + id + ", username=" + username + ", password=" + password + "]";
 }
 }
1. 引入Service接口
public interface UserService {
 /**
  * 根据ID获取用户
  * @param i
  * @return
  */
 User get(int id);
 /**
  * 查询所有用户
  * @return
  */
 List<User> findAll();
 /**
  * 新增用户
  * @param user
  */
 void add(User user);
}
1. 编写Controller
 @Controller
 @RequestMapping("/user")
 public class UserController {
 @Reference
 private UserService userService;
 @RequestMapping("/findUserList")
 public String findUserList(Model model) {
 List<User> list = userService.findAll();
 model.addAttribute("list", list);
 return "/index.jsp";
 }
 @RequestMapping("/add")
 public String add(User user) {
 userService.add(user);
 return "redirect:/user/findUserList";
 }
 }
  1. 编写入口
@SpringBootApplication
 public class Application {
 public static void main(String[] args) {
 SpringApplication.run(Application.class);
 }
 }
  1. 编写配置文件
server.port=10087
 server.context-path=/
 dubbo.annotation.package=com.itheima.springboot.controller
 dubbo.application.name=com.itheima.user.web
  1. 编写页面
<%@ page language="java" contentType="text/html; charset=UTF-8" pageEncoding="UTF-8"%>
 <%@ taglib prefix="c" uri="http://java.sun.com/jsp/jstl/core" %>
 <!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
 <html>
 <head>
 <meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
 <title>JSP测试</title>
 </head>
 <body>
 <table border="1">
 <form action="<%=request.getContextPath()%>/user/add" method="post">
 <tr>
 <td>用户名:<input type="text" name="username"/></td>
 <td>密码:<input type="text" name="password"/></td>
 <td><input type="submit" value="新增"/></td>
 </tr>
 </form>
 </table>
 <table border=1>
 <tr>
 <th>ID</th>
 <th>用户名</th>
 <th>密码</th>
 </tr>
 <c:forEach items="${list}" var="user">
 <tr>
 <td>${user.id}</td>
 <td>${user.username}</td>
 <td>${user.password}</td>
 </tr>
 </c:forEach>
 </table>
 </body>
 </html>
  1. 访问http://localhost:10087/user/findUserList

Spring Boot自动配置原理结构分析

通过实践,可以隐约感觉到。Spring Boot相当于基于Maven和Spring做了一个开发平台,使用这个平台可以减少配置、快速开发。那么Spring Boot到底是如何做到的呢?

回想,我们开发的第一个案例。我们只是往pom.xml中进行简单配置,就可以开始进行Spring开发了。

然后,更新项目可以看到,在Maven的依赖中,导入了很多的JAR包。

这两段配置怎么这么神奇,它到底做了什么?先来看看这个spring-boot-starter-parent的pom文件。

先是定义了很多的常量

里面还定义了一些依赖的版本锁定、插件的版本锁定。但没有导入具体的JAR包。

这个spring-boot-starter-parent从spring-boot-dependencies中继承,这个pom文件中定义了大量的版本号、以及版本锁定。

这些版本应该都是做过兼容性测试的,一般不要去修改否则出现不兼容问题是比较麻烦的。

再看看spring-boot-starter这个依赖

这个starter起步依赖中包含了导入了spring-boot依赖,spring-boot依赖导入了spring framework的核心依赖。

spring-boot-autoconfigure依赖,spring-boot-starter-logging会自动日志相关的依赖。

这个spring-boot-autoconfigure里面包含了很多玄机。

我猜想,Spring Boot是通过自动配置,来帮助我们自动创建了很多bean在IOC容器中。

所以接下来要回答两个问题:

1、Spring创建了哪些Bean?

2、因为我们之前都是通过编写很多的配置文件来创建和配置bean的,那Spring是如何读取配置来创建这些bean的?

接着猜:

以前的配置信息肯定还有,Spring不应该是把之前假设的平台全部推倒,而是把常用的配置整合起来了,就省去了我们自己来手动配置的过程。那么,我猜:每一个Starter都会有其对应的配置信息。我们来找一找spring-boot-starter的配置信息。

这个autoconfigure里面有大量的包,而且命名方式是以技术组件来命名的

要知道Spring Boot创建了哪些bean,直接去看自动配置包中,以Configuration结尾的类就可以了。要想看看具体application.properties中应该配置哪些属性,直接去看以properties文件结尾的类就可以了。

来看一段自动配置的源代码,下面这段代码是从JmsAutoConfiguration中截取出来的。

@Configuration
@ConditionalOnClass({ Message.class, JmsTemplate.class })
@ConditionalOnBean(ConnectionFactory.class)
@EnableConfigurationProperties(JmsProperties.class)
@Import(JmsAnnotationDrivenConfiguration.class)
public class JmsAutoConfiguration {
 @Configuration
 protected static class JmsTemplateConfiguration {
  private final JmsProperties properties;
  private final ObjectProvider<DestinationResolver> destinationResolver;
  private final ObjectProvider<MessageConverter> messageConverter;
  public JmsTemplateConfiguration(JmsProperties properties,
    ObjectProvider<DestinationResolver> destinationResolver,
    ObjectProvider<MessageConverter> messageConverter) {
   this.properties = properties;
   this.destinationResolver = destinationResolver;
   this.messageConverter = messageConverter;
  }
  @Bean
  @ConditionalOnMissingBean
  @ConditionalOnSingleCandidate(ConnectionFactory.class)
  public JmsTemplate jmsTemplate(ConnectionFactory connectionFactory) {
   JmsTemplate jmsTemplate = new JmsTemplate(connectionFactory);
   jmsTemplate.setPubSubDomain(this.properties.isPubSubDomain());
   DestinationResolver destinationResolver = this.destinationResolver
     .getIfUnique();
   if (destinationResolver != null) {
    jmsTemplate.setDestinationResolver(destinationResolver);
   }
   MessageConverter messageConverter = this.messageConverter.getIfUnique();
   if (messageConverter != null) {
    jmsTemplate.setMessageConverter(messageConverter);
   }
   JmsProperties.Template template = this.properties.getTemplate();
   if (template.getDefaultDestination() != null) {
    jmsTemplate.setDefaultDestinationName(template.getDefaultDestination());
   }
   if (template.getDeliveryDelay() != null) {
    jmsTemplate.setDeliveryDelay(template.getDeliveryDelay());
   }
   jmsTemplate.setExplicitQosEnabled(template.determineQosEnabled());
   if (template.getDeliveryMode() != null) {
    jmsTemplate.setDeliveryMode(template.getDeliveryMode().getValue());
   }
   if (template.getPriority() != null) {
    jmsTemplate.setPriority(template.getPriority());
   }
   if (template.getTimeToLive() != null) {
    jmsTemplate.setTimeToLive(template.getTimeToLive());
   }
   if (template.getReceiveTimeout() != null) {
    jmsTemplate.setReceiveTimeout(template.getReceiveTimeout());
   }
   return jmsTemplate;
  }
 }

这里面有几个很重要的注解

  1. @ConditionalOnClass
    这个注解表示,如果检测到当前的JVM中加载了Message.class, JmsTemplate.class,就加载该Java Config配置。
  2. @ConditionalOnMissingBean
    这个注解表示,如果IOC容器中没有检测到这个类型的Bean,就创建一个。如果检测到了,那么就不创建了。所以,如果我们自己配置了JmsTemplate这个Bean,那这个自动配置就失效了
  3. @ConditionalOnBean
    这个注解表示,如果IOC容器中有指定类型的Bean,才加载Java Config配置。例如:这里如果检测到容器中有ConnectionFactory类型的Bean,才会创建JmsTemplate。
  4. @EnableConfigurationProperties
    这个注解表示将以Properties结尾的配置类,加载到当前的自动配置类中。一般的Starter中的Properties类都可以从application.properties中的指定前缀的属性加载。从而让我们可以轻松的自定义里面的配置。
  5. @Import
    导入其他的Java Config配置,相当于之前XML配置中的import。

结尾

大家应该有一个直接的体会,Spring Boot真的让我们的工作更加轻松了。以前要写的很多配置、导很多的依赖,现在只需要短短几行代码就可以解决问题。而且,不再需要我们去考虑版本之间的兼容问题了。相信,很快大家编写的应用都会切换到Spring Boot。它将让我们将更多的精力放在编写、设计结构、算法上。

相关实践学习
基于MSE实现微服务的全链路灰度
通过本场景的实验操作,您将了解并实现在线业务的微服务全链路灰度能力。
相关文章
|
1月前
|
XML Java 开发者
Spring Boot开箱即用可插拔实现过程演练与原理剖析
【11月更文挑战第20天】Spring Boot是一个基于Spring框架的项目,其设计目的是简化Spring应用的初始搭建以及开发过程。Spring Boot通过提供约定优于配置的理念,减少了大量的XML配置和手动设置,使得开发者能够更专注于业务逻辑的实现。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,为开发者提供一个全面的理解。
34 0
|
7天前
|
NoSQL Java Redis
Spring Boot 自动配置机制:从原理到自定义
Spring Boot 的自动配置机制通过 `spring.factories` 文件和 `@EnableAutoConfiguration` 注解,根据类路径中的依赖和条件注解自动配置所需的 Bean,大大简化了开发过程。本文深入探讨了自动配置的原理、条件化配置、自定义自动配置以及实际应用案例,帮助开发者更好地理解和利用这一强大特性。
49 14
|
22天前
|
XML Java 数据格式
Spring Core核心类库的功能与应用实践分析
【12月更文挑战第1天】大家好,今天我们来聊聊Spring Core这个强大的核心类库。Spring Core作为Spring框架的基础,提供了控制反转(IOC)和依赖注入(DI)等核心功能,以及企业级功能,如JNDI和定时任务等。通过本文,我们将从概述、功能点、背景、业务点、底层原理等多个方面深入剖析Spring Core,并通过多个Java示例展示其应用实践,同时指出对应实践的优缺点。
48 14
|
23天前
|
Java 关系型数据库 数据库
京东面试:聊聊Spring事务?Spring事务的10种失效场景?加入型传播和嵌套型传播有什么区别?
45岁老架构师尼恩分享了Spring事务的核心知识点,包括事务的两种管理方式(编程式和声明式)、@Transactional注解的五大属性(transactionManager、propagation、isolation、timeout、readOnly、rollbackFor)、事务的七种传播行为、事务隔离级别及其与数据库隔离级别的关系,以及Spring事务的10种失效场景。尼恩还强调了面试中如何给出高质量答案,推荐阅读《尼恩Java面试宝典PDF》以提升面试表现。更多技术资料可在公众号【技术自由圈】获取。
|
20天前
|
XML 前端开发 安全
Spring MVC:深入理解与应用实践
Spring MVC是Spring框架提供的一个用于构建Web应用程序的Model-View-Controller(MVC)实现。它通过分离业务逻辑、数据、显示来组织代码,使得Web应用程序的开发变得更加简洁和高效。本文将从概述、功能点、背景、业务点、底层原理等多个方面深入剖析Spring MVC,并通过多个Java示例展示其应用实践,同时指出对应实践的优缺点。
48 2
|
28天前
|
JSON 安全 算法
Spring Boot 应用如何实现 JWT 认证?
Spring Boot 应用如何实现 JWT 认证?
65 8
|
26天前
|
消息中间件 Java Kafka
Spring Boot 与 Apache Kafka 集成详解:构建高效消息驱动应用
Spring Boot 与 Apache Kafka 集成详解:构建高效消息驱动应用
39 1
|
27天前
|
JavaScript Java 关系型数据库
Spring事务失效的8种场景
本文总结了使用 @Transactional 注解时事务可能失效的几种情况,包括数据库引擎不支持事务、类未被 Spring 管理、方法非 public、自身调用、未配置事务管理器、设置为不支持事务、异常未抛出及异常类型不匹配等。针对这些情况,文章提供了相应的解决建议,帮助开发者排查和解决事务不生效的问题。
|
29天前
|
Java 容器
springboot自动配置原理
启动类@SpringbootApplication注解下,有三个关键注解 (1)@springbootConfiguration:表示启动类是一个自动配置类 (2)@CompontScan:扫描启动类所在包外的组件到容器中 (3)@EnableConfigutarion:最关键的一个注解,他拥有两个子注解,其中@AutoConfigurationpackageu会将启动类所在包下的所有组件到容器中,@Import会导入一个自动配置文件选择器,他会去加载META_INF目录下的spring.factories文件,这个文件中存放很大自动配置类的全类名,这些类会根据元注解的装配条件生效,生效
|
1月前
|
Java Docker 微服务
利用Docker容器化部署Spring Boot应用
利用Docker容器化部署Spring Boot应用
51 0

热门文章

最新文章