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

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
云数据库 RDS MySQL,高可用系列 2核4GB
MSE Nacos/ZooKeeper 企业版试用,1600元额度,限量50份
简介: 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。它将让我们将更多的精力放在编写、设计结构、算法上。

相关文章
|
2月前
|
Java Spring 容器
SpringBoot自动配置的原理是什么?
Spring Boot自动配置核心在于@EnableAutoConfiguration注解,它通过@Import导入配置选择器,加载META-INF/spring.factories中定义的自动配置类。这些类根据@Conditional系列注解判断是否生效。但Spring Boot 3.0后已弃用spring.factories,改用新格式的.imports文件进行配置。
721 0
|
2月前
|
Java Spring
Spring Boot配置的优先级?
在Spring Boot项目中,配置可通过配置文件和外部配置实现。支持的配置文件包括application.properties、application.yml和application.yaml,优先级依次降低。外部配置常用方式有Java系统属性(如-Dserver.port=9001)和命令行参数(如--server.port=10010),其中命令行参数优先级高于系统属性。整体优先级顺序为:命令行参数 &gt; Java系统属性 &gt; application.properties &gt; application.yml &gt; application.yaml。
500 0
|
24天前
|
Java 关系型数据库 数据库
深度剖析【Spring】事务:万字详解,彻底掌握传播机制与事务原理
在Java开发中,Spring框架通过事务管理机制,帮我们轻松实现了这种“承诺”。它不仅封装了底层复杂的事务控制逻辑(比如手动开启、提交、回滚事务),还提供了灵活的配置方式,让开发者能专注于业务逻辑,而不用纠结于事务细节。
|
1月前
|
安全 算法 Java
在Spring Boot中应用Jasypt以加密配置信息。
通过以上步骤,可以在Spring Boot应用中有效地利用Jasypt对配置信息进行加密,这样即使配置文件被泄露,其中的敏感信息也不会直接暴露给攻击者。这是一种在不牺牲操作复杂度的情况下提升应用安全性的简便方法。
576 10
|
2月前
|
人工智能 安全 Java
Spring Boot yml 配置敏感信息加密
本文介绍了如何在 Spring Boot 项目中使用 Jasypt 实现配置文件加密,包含添加依赖、配置密钥、生成加密值、在配置中使用加密值及验证步骤,并提供了注意事项,确保敏感信息的安全管理。
707 1
|
2月前
|
缓存 安全 Java
Spring 框架核心原理与实践解析
本文详解 Spring 框架核心知识,包括 IOC(容器管理对象)与 DI(容器注入依赖),以及通过注解(如 @Service、@Autowired)声明 Bean 和注入依赖的方式。阐述了 Bean 的线程安全(默认单例可能有安全问题,需业务避免共享状态或设为 prototype)、作用域(@Scope 注解,常用 singleton、prototype 等)及完整生命周期(实例化、依赖注入、初始化、销毁等步骤)。 解析了循环依赖的解决机制(三级缓存)、AOP 的概念(公共逻辑抽为切面)、底层动态代理(JDK 与 Cglib 的区别)及项目应用(如日志记录)。介绍了事务的实现(基于 AOP
104 0
|
2月前
|
监控 架构师 NoSQL
spring 状态机 的使用 + 原理 + 源码学习 (图解+秒懂+史上最全)
spring 状态机 的使用 + 原理 + 源码学习 (图解+秒懂+史上最全)
|
2月前
|
SQL XML Java
配置Spring框架以连接SQL Server数据库
最后,需要集成Spring配置到应用中,这通常在 `main`方法或者Spring Boot的应用配置类中通过加载XML配置或使用注解来实现。
233 0
|
4月前
|
前端开发 Java 数据库连接
Spring核心原理剖析与解说
每个部分都是将一种巨大并且复杂的技术理念传达为更易于使用的接口,而这就是Spring的价值所在,它能让你专注于开发你的应用,而不必从头开始设计每一部分。
165 32
|
2月前
|
XML 人工智能 IDE
Springboot整合SSMP报错分析
本文介绍了Springboot整合SSMP框架时常见的报错及解决方案,包括MyBatis-Plus版本不兼容导致的Lambda表达式条件构造器报错及表名不匹配问题。通过升级或降级MyBatis-Plus版本、使用@TableName注解或配置table-prefix属性,可有效解决上述问题,帮助开发者避免在整合SSMP时出现不必要的错误。
160 0