您现在的位置是:主页 > news > 番禺网站建设设计/推广app的平台
番禺网站建设设计/推广app的平台
admin2025/4/19 16:54:08【news】
简介番禺网站建设设计,推广app的平台,长沙 学校网站建设,网站建设及应用实施方案目录我的springboot web项目工程目录如下:POM文件如下:YAML配置文件如下:在annotation包中创建自定义注解DataSource:在enums包中创建枚举类DataSourcesType:在core.aop包中创建切面类DynamicDataSourceAspect…
番禺网站建设设计,推广app的平台,长沙 学校网站建设,网站建设及应用实施方案目录我的springboot web项目工程目录如下:POM文件如下:YAML配置文件如下:在annotation包中创建自定义注解DataSource:在enums包中创建枚举类DataSourcesType:在core.aop包中创建切面类DynamicDataSourceAspect…
目录
- 我的springboot web项目工程目录如下:
- POM文件如下:
- YAML配置文件如下:
- 在annotation包中创建自定义注解DataSource:
- 在enums包中创建枚举类DataSourcesType:
- 在core.aop包中创建切面类DynamicDataSourceAspect:
- 在core.datasource包中创建动态数据源类DynamicDataSource和数据源切换处理类DynamicDataSourceContextHolder:
- 在core.druid包中创建数据源配置类DataSourceConfiguration和数据源配置文件类DataSourceProperties:
- 在启动类StudyApplication加入注解,解决循环依赖:
- 添加Controller测试类:
- 自己在mysql中建立一个user表,进行测试。
- 在浏览器输入地址,查看结果:
- 后台程序打印日志:
我的springboot web项目工程目录如下:
POM文件如下:
<?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"><modelVersion>4.0.0</modelVersion><groupId>cn.example</groupId><artifactId>SpringBootStudy</artifactId><version>1.0-SNAPSHOT</version><packaging>war</packaging><name>SpringBootStudy Maven Webapp</name><!-- FIXME change it to the project's website --><url>http://www.example.com</url><properties><project.build.sourceEncoding>UTF-8</project.build.sourceEncoding><maven.compiler.source>1.8</maven.compiler.source><maven.compiler.target>1.8</maven.compiler.target><!--自定义配置--><druid.starter.version>1.1.16</druid.starter.version></properties><!-- Inherit defaults from Spring Boot --><parent><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-parent</artifactId><version>2.3.3.RELEASE</version></parent><!-- Add typical dependencies for a web application --><dependencies><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-web</artifactId></dependency><!-- 配置注解执行器配置完成后,当执行类中已经定义了对象和该对象的字段后,在配置文件中对该类赋值时,便会非常方便的弹出提示信息 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-configuration-processor</artifactId><optional>true</optional></dependency><dependency><groupId>org.projectlombok</groupId><artifactId>lombok</artifactId></dependency><!-- jdbcTemplate --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-jdbc</artifactId></dependency><!-- MySQL连接 --><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><scope>runtime</scope></dependency><!--引入druid数据源--><dependency><groupId>com.alibaba</groupId><artifactId>druid-spring-boot-starter</artifactId><version>${druid.starter.version}</version></dependency><!-- 测试 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-test</artifactId><scope>test</scope></dependency><!-- 切面 --><dependency><groupId>org.springframework.boot</groupId><artifactId>spring-boot-starter-aop</artifactId></dependency><dependency><groupId>org.aspectj</groupId><artifactId>aspectjrt</artifactId></dependency></dependencies><!-- Package as an executable jar --><build><plugins><plugin><groupId>org.springframework.boot</groupId><artifactId>spring-boot-maven-plugin</artifactId></plugin></plugins></build>
</project>
YAML配置文件如下:
spring:profiles:active: devdatasource:driver-class-name: com.mysql.cj.jdbc.Drivertype: com.alibaba.druid.pool.DruidDataSource #修改数据源为Druiddruid:master:url: jdbc:mysql://localhost:3306/study?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&zeroDateTimeBehavior=convertToNullusername: rootpassword: rootslave:enable: trueurl: jdbc:mysql://localhost:3306/study?autoReconnect=true&useUnicode=true&characterEncoding=utf-8&serverTimezone=UTC&zeroDateTimeBehavior=convertToNullusername: rootpassword: rootinitialSize: 3 #修改Druid的默认连接配置minIdle: 10 # 最小连接池数量maxActive: 20 # 最大连接池数量maxWait: 60000 # 配置获取连接等待超时的时间timeBetweenEvictionRunsMillis: 60000 # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒minEvictableIdleTimeMillis: 300000 # 配置一个连接在池中最小生存的时间,单位是毫秒maxEvictableIdleTimeMillis: 900000 # 配置一个连接在池中最大生存的时间,单位是毫秒
在annotation包中创建自定义注解DataSource:
package cn.xhh.study.common.annotation;import cn.xhh.study.common.enums.DataSourcesType;import java.lang.annotation.*;/*** 数据源自定义注解* @author Administrator*/
@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Inherited
public @interface DataSource {DataSourcesType name() default DataSourcesType.MASTER;
}
在enums包中创建枚举类DataSourcesType:
package cn.xhh.study.common.enums;/*** 数据源类型* @author Administrator*/
public enum DataSourcesType {/*** 主库*/MASTER,/*** 从库*/SLAVE
}
在core.aop包中创建切面类DynamicDataSourceAspect:
package cn.xhh.study.core.aop;import cn.xhh.study.common.annotation.DataSource;
import cn.xhh.study.core.datasource.DynamicDataSourceContextHolder;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.core.annotation.Order;
import org.springframework.stereotype.Component;import java.lang.reflect.Method;/*** 1.@Order(-1)保证该AOP在@Transactional之前执行* @author Administrator*/
@Aspect
@Component
@Order(-1)
public class DynamicDataSourceAspect {protected Logger logger = LoggerFactory.getLogger(getClass());@Pointcut("@annotation(cn.xhh.study.common.annotation.DataSource)"+ "|| @within(cn.xhh.study.common.annotation.DataSource)")public void dsPointCut() {}@Around("dsPointCut()")public Object around(ProceedingJoinPoint point) throws Throwable {Method targetMethod = this.getTargetMethod(point);//获取要切换的数据源DataSource dataSource = targetMethod.getAnnotation(DataSource.class);if (dataSource != null) {DynamicDataSourceContextHolder.setDataSourceType(dataSource.name().name());}try {return point.proceed();}finally {// 销毁数据源 在执行方法之后DynamicDataSourceContextHolder.removeDataSourceType();}}/*** 获取目标方法*/private Method getTargetMethod(ProceedingJoinPoint pjp) throws NoSuchMethodException {Signature signature = pjp.getSignature();MethodSignature methodSignature = (MethodSignature) signature;Method agentMethod = methodSignature.getMethod();return pjp.getTarget().getClass().getMethod(agentMethod.getName(), agentMethod.getParameterTypes());}
}
在core.datasource包中创建动态数据源类DynamicDataSource和数据源切换处理类DynamicDataSourceContextHolder:
package cn.xhh.study.core.datasource;import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;/*** 获取数据源(依赖于 spring)* 定义一个类继承AbstractRoutingDataSource实现determineCurrentLookupKey方法,该方法可以实现数据库的动态切换* @author Administrator*/
public class DynamicDataSource extends AbstractRoutingDataSource {public static DynamicDataSource build() {return new DynamicDataSource();}/*** 获取与数据源相关的key* 此key是Map<String,DataSource> resolvedDataSources 中与数据源绑定的key值* 在通过determineTargetDataSource获取目标数据源时使用*/@Overrideprotected Object determineCurrentLookupKey() {return DynamicDataSourceContextHolder.getDataSourceType();}}
package cn.xhh.study.core.datasource;import org.slf4j.Logger;
import org.slf4j.LoggerFactory;/*** 数据源切换处理* @author Administrator*/
public class DynamicDataSourceContextHolder {public static final Logger log = LoggerFactory.getLogger(DynamicDataSourceContextHolder.class);/***此类提供线程局部变量。这些变量不同于它们的正常对应关系是每个线程访问一个线程(通过get、set方法),有自己的独立初始化变量的副本。*/private static final ThreadLocal<String> contextHolder = new ThreadLocal<>();/*** 设置当前线程的数据源变量*/public static void setDataSourceType(String dataSourceType) {log.info("已切换到{}数据源", dataSourceType);contextHolder.set(dataSourceType);}/*** 获取当前线程的数据源变量*/public static String getDataSourceType() {return contextHolder.get();}/*** 删除与当前线程绑定的数据源变量*/public static void removeDataSourceType() {contextHolder.remove();}}
在core.druid包中创建数据源配置类DataSourceConfiguration和数据源配置文件类DataSourceProperties:
package cn.xhh.study.core.druid;import cn.xhh.study.common.enums.DataSourcesType;
import cn.xhh.study.core.datasource.DynamicDataSource;
import cn.xhh.study.core.druid.DataSourceProperties;
import com.alibaba.druid.spring.boot.autoconfigure.DruidDataSourceBuilder;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.DependsOn;
import org.springframework.context.annotation.Primary;import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;/*** 数据源配置类* @author Administrator*/
@Configuration
public class DataSourceConfiguration {/*** 主库*/@Bean@ConfigurationProperties("spring.datasource.druid.master")public DataSource masterDataSource(DataSourceProperties dataSourceProperties) {return dataSourceProperties.setDataSource(DruidDataSourceBuilder.create().build());}/*** 从库* @param dataSourceProperties* @return DataSource*/@Bean@ConditionalOnProperty( prefix = "spring.datasource.druid.slave", name = "enable", havingValue = "true")//是否开启数据源开关---若不开启 默认适用默认数据源@ConfigurationProperties("spring.datasource.druid.slave")public DataSource slaveDataSource(DataSourceProperties dataSourceProperties) {return dataSourceProperties.setDataSource(DruidDataSourceBuilder.create().build());}/*** 1.@DependsOn({"masterDataSource","slaveDataSource"})配合Springboot启动类,解决Druid多数据源循环依赖的问题* 设置数据源*/@Bean(name = "dynamicDataSource")@Primary@DependsOn({"masterDataSource","slaveDataSource"})public DynamicDataSource dynamicDataSource(DataSource masterDataSource, DataSource slaveDataSource) {Map<Object, Object> targetDataSources = new HashMap<>();DynamicDataSource dynamicDataSource = DynamicDataSource.build();targetDataSources.put(DataSourcesType.MASTER.name(), masterDataSource);targetDataSources.put(DataSourcesType.SLAVE.name(), slaveDataSource);//默认数据源配置 DefaultTargetDataSourcedynamicDataSource.setDefaultTargetDataSource(masterDataSource);//额外数据源配置 TargetDataSourcesdynamicDataSource.setTargetDataSources(targetDataSources);dynamicDataSource.afterPropertiesSet();return dynamicDataSource;}
}
package cn.xhh.study.core.druid;import com.alibaba.druid.pool.DruidDataSource;
import lombok.Setter;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;/*** 数据源配置文件* @author Administrator*/
@Setter
@Configuration
@ConfigurationProperties(prefix = "spring.datasource.druid")
public class DataSourceProperties {private int initialSize;private int minIdle;private int maxActive;private int maxWait;private int timeBetweenEvictionRunsMillis;private int minEvictableIdleTimeMillis;private int maxEvictableIdleTimeMillis;private String validationQuery;private boolean testWhileIdle;private boolean testOnBorrow;private boolean testOnReturn;public DruidDataSource setDataSource(DruidDataSource datasource) {// 配置初始化大小、最小、最大datasource.setInitialSize(initialSize);datasource.setMaxActive(maxActive);datasource.setMinIdle(minIdle);// 配置获取连接等待超时的时间datasource.setMaxWait(maxWait);// 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);// 配置一个连接在池中最小、最大生存的时间,单位是毫秒datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);/*** 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。*/datasource.setValidationQuery(validationQuery);/** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */datasource.setTestWhileIdle(testWhileIdle);/** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */datasource.setTestOnBorrow(testOnBorrow);/** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */datasource.setTestOnReturn(testOnReturn);return datasource;}
}
在启动类StudyApplication加入注解,解决循环依赖:
package cn.xhh.study;import cn.xhh.study.servlet.listener.MyListener;
import cn.xhh.study.servlet.MyServlet;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.jdbc.DataSourceAutoConfiguration;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.boot.web.servlet.ServletListenerRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;/*** 1.@ServletComponentScan:启动对自定义servlet的扫描* 2.添加(exclude = {DataSourceAutoConfiguration.class}),解决在配置Druid多数据源时,出现循环依赖的问题* @author Administrator*/
@ServletComponentScan
@SpringBootApplication(exclude = {DataSourceAutoConfiguration.class})
public class StudyApplication {public static void main(String[] args) {SpringApplication.run(StudyApplication.class, args);}
}
添加Controller测试类:
package cn.xhh.study.controller;import cn.xhh.study.common.annotation.DataSource;
import cn.xhh.study.common.enums.DataSourcesType;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Controller;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.ResponseBody;import java.util.List;
import java.util.Map;/*** @author Administrator*/
@Controller
public class JdbcTemplateController {private JdbcTemplate jdbcTemplate;public JdbcTemplateController(JdbcTemplate jdbcTemplate) {this.jdbcTemplate = jdbcTemplate;}@ResponseBody@RequestMapping("queryUserForList")@DataSource(name = DataSourcesType.SLAVE)public List<Map<String, Object>> getData() {String sql = "select * from user";List<Map<String, Object>> maps = jdbcTemplate.queryForList(sql);return maps;}
}
自己在mysql中建立一个user表,进行测试。
在浏览器输入地址,查看结果:
http://localhost:8081/queryUserForList
后台程序打印日志:
2021-12-08 10:58:13.400 INFO 7284 --- [nio-8081-exec-1] c.x.s.c.d.DynamicDataSourceContextHolder : 已切换到SLAVE数据源
Druid多数据源配置成功!