Spring Boot 示例项目
Spring Boot 基于注解式开发 maven REST 示例项目
项目地址:https://github.com/windwant/spring-boot-service
项目地址:https://github.com/windwant/spring-dubbo-service
项目特色:
1. servlet、listener、interceptor、filter 配置
2. mybatis 配置集成,多数据源 RouingDataSource
3. 集成 jmx 监控 MBean
4. 定时任务配置 Scheduled
5. aop 配置
6. ftp 服务 FTPTranport
7. 测试 SpringBootTest
8. Metrics 监控
9. 参数验证 javax.validation hibernate.validator
a) 测试:/hellox?name=
10. 跨域处理 Cors
11. 权限控制 shiro 权限框架
a) 测试用户:userName: admin passwd: admin
b) 验证码:/login/checkcode
c) 登录:/login?userName=&passwd=&code=
d) 测试:/hellox?name=
12. 导出 Excel SXSSFWorkBook 海量数据导出
a) 测试:/export
13. Consul 服务注册与发现;
a) 服务启动注册到 consul;
b) 测试获取 redis 服务,初始化 redis 资源;
c) consul 监控 redis 服务;
d) 注意 consul 客户端和 consul 程序版本问题
14. reids 分布式锁
a) lua 脚本 获取 redis 分布式锁
15. SPI 机制:org/windwant/spring/core/spi
a) 运行时配置:META-INF/services/org.windwant.spring.core.spi.Calc
16. static 资源,“/”映射
17. 使用 druid 数据源连接池;配置 druid 数据源监控:http://localhost:8081/druid/index.html
18. Dubbo RPC 服务
一、 Web servlet、listener、interceptor 等
1. servlet:
启动类添加注解 @ServletComponentScan
编写 servlet:
@WebServlet("/web")
public class BootSevlet implements Servlet {
...
2. Interceptor:
编写:
/**
* BootInterceptor
*/
public class BootInterceptor implements HandlerInterceptor {
...
注册:WebMvcConfigurerAdapter->addInterceptor 方法。
@Configuration
public class ApplicationConfig {
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new BootInterceptor()).addPathPatterns("/**");
super.addInterceptors(registry);
}
...
3. listenenr:实现各种 listener
@WebListener
public class BootListener implements ServletContextListener {
...
二、mybatis 配置集成,多数据源配置
配置文件:
1. 接口方式开发 dao,扫描包配置 :@MapperScan(basePackages = "org.windwant.spring.mapper")
2. 配置 dataSource,sqlSessionFactory
datasource 根据 application.yml 配置的数据源配置
application.yml
datasource:
local:
url: $[datasource.local.url]
username: $[datasource.local.user]
password: $[datasource.local.password]
driverClassName: com.mysql.jdbc.Driver
type: org.apache.commons.dbcp.BasicDataSource
max-active: 30
max-idle: 10
max-wait: 10
test-while-idle: true
remote:
url: $[datasource.remote.url]
username: $[datasource.remote.user]
password: $[datasource.remote.password]
driverClassName: com.mysql.jdbc.Driver
type: org.apache.commons.dbcp.BasicDataSource
max-active: 30
max-idle: 10
max-wait: 10
test-while-idle: true
DataSource 注解配置:
/**
* Created by windwant on 2016/12/30.
* implements EnvironmentAware, ApplicationContextAware
*/
@Configuration
public class MybatisConfig {
// private Environment environment;
//
// @Override
// public void setEnvironment(Environment environment) {
// this.environment = environment;
// }
@Primary
@Bean(name = "localDataSource")
@Order(value = 1)
@ConfigurationProperties(prefix = "datasource.local")
public DataSource localDataSource(){
return DataSourceBuilder.create().build();
}
@Order(value = 2)
@Bean(name = "remoteDataSource")
@ConfigurationProperties(prefix = "datasource.remote")
public DataSource remoteDataSource() {
return DataSourceBuilder.create().build();
}
@Bean(name = "routingDataSource")
@Order(value = 3)
public DataSource routingDataSource(@Qualifier("localDataSource") DataSource localDataSource,
@Qualifier("remoteDataSource")BasicDataSource remoteDataSource){
RoutingDataSource routingDataSource = new RoutingDataSource();
Map<Object, Object> dataSources = new HashMap<>();
dataSources.put(Type.LOCAL.name(), localDataSource);
dataSources.put(Type.REMOTE.name(), remoteDataSource);
routingDataSource.setTargetDataSources(dataSources);
routingDataSource.setDefaultTargetDataSource(localDataSource);
return routingDataSource;
}
@Bean
@Order(value = 4)
@Lazy
public SqlSessionFactory sqlSessionFactory(@Qualifier("remoteDataSource") DataSource remoteDataSource,
@Qualifier("localDataSource") DataSource localDataSource,
@Qualifier("routingDataSource")DataSource routingDataSource) throws Exception {
SqlSessionFactoryBean factoryBean = new SqlSessionFactoryBean();
factoryBean.setDataSource(routingDataSource);
factoryBean.getObject().getConfiguration().setMapUnderscoreToCamelCase(true);
factoryBean.setMapperLocations(new PathMatchingResourcePatternResolver().getResources("classpath*:mybatis/*.xml"));
factoryBean.afterPropertiesSet();
return factoryBean.getObject();
}
// private ApplicationContext ctx;
//
// @Override
// public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
// this.ctx = applicationContext;
// }
}
项目添加 Bean 配置:
@Bean
public MapperScannerConfigurer mapperScannerConfigurer() {
MapperScannerConfigurerProxy mapperScannerConfigurerProxy = new MapperScannerConfigurerProxy();
mapperScannerConfigurerProxy.setBasePackage("org.windwant.spring.mapper");
return mapperScannerConfigurerProxy;
}
三、集成 jmx 监控 MBean
/**
* Created by windwant on 2017/4/6.
* JMX Mbean 监控 可以通过 jconsole 进行 mbean 暴露操作
*/
@Component
@ManagedResource(description = "sboot svr")
public class WAMBean {
// 属性
private String name;
private int age;
private String message;
@ManagedAttribute
public String getName() {
System.out.println("name: " + name);
return name;
}
@ManagedAttribute
public void setName(String name) {
this.name = name;
}
@ManagedAttribute
public int getAge() {
System.out.println("age: "+age);
return age;
}
@ManagedAttribute
public void setAge(int age) {
this.age = age;
}
@ManagedAttribute
public String getMessage() {
System.out.println("message: " + message);
return message;
}
@ManagedAttribute
public void setMessage(String message) {
this.message = message;
}
@ManagedOperation
@ManagedOperationParameter(name = "message", description ="message")
public void call(String message) {
System.out.println("call:" + message);
}
@ManagedOperation
@ManagedOperationParameter(name = "who", description ="who")
@ManagedOperationParameter(name = "what", description ="what")
public void look(String who, String what){
System.out.println(who + " 发现了 " + what);
}
@Autowired
FTPTransport ftpTransport;
@ManagedOperation
public void upload() throws FileNotFoundException {
FileInputStream f = null;
try {
f = new FileInputStream(new File("D:\\a.json"));
ftpTransport.uploadFile("ajson", f);
}catch (Exception e){
e.printStackTrace();
}finally {
try {
if(f != null){
f.close();
}
}catch (Exception e){
e.printStackTrace();
}
}
System.out.println("to play....");
}
}
四:定时任务配置 Scheduled
@Component
public class BootJob {
private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH🇲🇲ss");
@Scheduled(fixedRate = 1000)
public void reportTime(){
System.out.println("current time is: " + dateFormat.format(new Date()));
}
}
五:参数验证
参数 Bean:验证注解 @NotBlank @NotNull 等
public class Guest {
@NotBlank(message = "{guest.name}")
private String name;
private Integer sex;
Controller:参数添加 @Valid 注解
@RequestMapping("/hellox")
Map<String, Object> hellox(@Valid Guest guest, BindingResult result){
if(result.hasErrors()){
return Response.response(-1, Constants.FAILED, result.getAllErrors());
}
使用 lang 验证提示信息:
@Bean
public LocalValidatorFactoryBean localValidatorFactoryBean(){
LocalValidatorFactoryBean localValidatorFactoryBean = new LocalValidatorFactoryBean();
localValidatorFactoryBean.setProviderClass(HibernateValidator.class);
ReloadableResourceBundleMessageSource rrbms = new ReloadableResourceBundleMessageSource();
rrbms.setBasename("classpath:/lang/messages");
rrbms.setUseCodeAsDefaultMessage(false);
rrbms.setDefaultEncoding("UTF-8");
localValidatorFactoryBean.setValidationMessageSource(rrbms);
return localValidatorFactoryBean;
}
六:跨域处理 Cors
配置 WebMvcConfigureAdapter addCorsMappings
addMapping:请求拦截
allowedOrigins:拦截请求源
allowedMethods:拦截方法
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
public void addInterceptors(InterceptorRegistry registry) {
registry.addInterceptor(new BootInterceptor()).addPathPatterns("/**");
super.addInterceptors(registry);
}
/**
* 跨域处理 映射所有路径 允许所有来源 以下方法请求
* @param registry
*/
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/**")
.allowedOrigins("*")
.allowedMethods("GET","POST","PUT","OPTIONS","DELETE","PATCH");
}
七:shiro 权限配置
@Configuration
public class ShiroConfig implements EnvironmentAware {
private final static int REMEMBER_ME_MAX_AGE = 365 * 24 * 3600;
// 这是个 DestructionAwareBeanPostProcessor 的子类,负责 org.apache.shiro.util.Initializable 类型 bean 的生命周期的,
// 初始化和销毁。主要是 AuthorizingRealm 类的子类,以及 EhCacheManager 类
@Bean(name = "lifecycleBeanPostProcessor")
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
}
@Bean
public SimpleCookie rememberMeCookie(){
SimpleCookie simpleCookie = new SimpleCookie("rememberMe");
simpleCookie.setMaxAge(REMEMBER_ME_MAX_AGE);
return simpleCookie;
}
@Bean
public CookieRememberMeManager rememberMeManager(){
CookieRememberMeManager cookieRememberMeManager = new CookieRememberMeManager();
cookieRememberMeManager.setCookie(rememberMeCookie());
//rememberMe cookie 加密的密钥 建议每个项目都不一样 默认 AES 算法 密钥长度 (128 256 512 位)
cookieRememberMeManager.setCipherKey(Base64.decode("2AvVhdsgUs0FSA3SDFAdag=="));
return cookieRememberMeManager;
}
// 为了对密码进行编码的,防止密码在数据库里明码保存,当然在登陆认证,这个类也负责对 form 里输入的密码进行编码。
@Bean(name = "hashedCredentialsMatcher")
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher credentialsMatcher = new ComHashedCredentialsMatcher();
credentialsMatcher.setHashAlgorithmName("MD5");// 散列算法: 这里使用 MD5 算法;
credentialsMatcher.setHashIterations(1);// 散列的次数,比如散列两次,相当于 md5(md5(""));
credentialsMatcher.setStoredCredentialsHexEncoded(true);//true 时密码加密用的是 Hex 编码;false 时用 Base64 编码
return credentialsMatcher;
}
// 增加缓存减少对数据库的查询压力
@Bean(name = "ehcacheManager")
public EhCacheManager getEhCacheManager() {
EhCacheManager em = new EhCacheManager();
em.setCacheManagerConfigFile("classpath:ehcache-shiro.xml");
return em;
}
// 自定义的认证类,继承自 AuthorizingRealm,负责用户的认证和权限的处理
@Bean(name = "shiroRealm")
public MyAuthorizingRealm shiroRealm() {
MyAuthorizingRealm realm = new MyAuthorizingRealm();
realm.setCredentialsMatcher(hashedCredentialsMatcher());
realm.setCachingEnabled(true);
realm.setCacheManager(getEhCacheManager());
return realm;
}
// 权限管理,这个类组合了登陆,登出,权限,session 的处理
@Bean(name = "securityManager")
public DefaultWebSecurityManager securityManager(){
DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager();
securityManager.setRealm(shiroRealm());
securityManager.setCacheManager(getEhCacheManager());
securityManager.setRememberMeManager(rememberMeManager());
DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
defaultWebSessionManager.setGlobalSessionTimeout(Long.parseLong(environment.getProperty("session.timeout")));
securityManager.setSessionManager(defaultWebSessionManager);
return securityManager;
}
// 开启 Shiro 的注解 (如 @RequiresRoles,@RequiresPermissions), 需借助 SpringAOP 扫描使用 Shiro 注解的类, 并在必要时进行安全逻辑验证 * 配置以下
// 两个 bean(DefaultAdvisorAutoProxyCreator( 可选) 和 AuthorizationAttributeSourceAdvisor) 即可实现此功能
@Bean(name = "advisorAutoProxyCreator")
@DependsOn({"lifecycleBeanPostProcessor"})
public DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator(){
DefaultAdvisorAutoProxyCreator advisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
advisorAutoProxyCreator.setProxyTargetClass(true);
return advisorAutoProxyCreator;
}
@Bean(name = "authorizationAttributeSourceAdvisor")
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor(){
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
}
@Bean(name = "shiroFilter")
public ShiroFilterFactoryBean shiroFilterFactoryBean() {
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean();
shiroFilterFactoryBean.getFilters().put("comauth", new ComAuthFilter());
shiroFilterFactoryBean.setSecurityManager(securityManager());
shiroFilterFactoryBean.setLoginUrl("/");
shiroFilterFactoryBean.setSuccessUrl("/index");
shiroFilterFactoryBean.setUnauthorizedUrl("/notlogin");
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<String, String>();
filterChainDefinitionMap.put("/","user");
filterChainDefinitionMap.put("/css/**","anon");
filterChainDefinitionMap.put("/js/**","anon");
filterChainDefinitionMap.put("/img/**","anon");
filterChainDefinitionMap.put("/","anon");
filterChainDefinitionMap.put("/**.html","anon");
filterChainDefinitionMap.put("/login","anon");
filterChainDefinitionMap.put("/login/checkcode","anon");
filterChainDefinitionMap.put("/login/notlogin","anon");
filterChainDefinitionMap.put("/export","anon");
filterChainDefinitionMap.put("/spiCalc","anon");
filterChainDefinitionMap.put("/hello/**","anon"); // 配置不控制权限请求 anon
filterChainDefinitionMap.put("/hellox","anon");
filterChainDefinitionMap.put("/","anon");
filterChainDefinitionMap.put("/**","comauth");
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap);
return shiroFilterFactoryBean;
}
private Environment environment;
@Override
public void setEnvironment(Environment environment) {
this.environment = environment;
}
}
八、Consul 服务注册与发现
/**
* consul agent -server -bootstrap-expect=1 -data-dir=data -node=server0 -bind=127.0.0.1 -client 0.0.0.0 -ui
* Created by windwant on 2016/8/18.
*/
@Component
public class ConsulMgr {
private static final Logger logger = LoggerFactory.getLogger(ConsulMgr.class);
@org.springframework.beans.factory.annotation.Value("${consul.host}")
private String consulHost;
@org.springframework.beans.factory.annotation.Value("${server.port}")
private Integer port;
@org.springframework.beans.factory.annotation.Value("${redis.host}")
private String redisHost;
@org.springframework.beans.factory.annotation.Value("${redis.port}")
private Integer redisPort;
private KeyValueClient keyValueClient;
private HealthClient healthClient;
private AgentClient agentClient;
private CatalogClient catalogClient;
private String redisService = "redis";
private String bootService = "boot";
public void init(){
Consul consul = Consul.builder()
.withConnectTimeoutMillis(3000)
.withPing(true)
.withReadTimeoutMillis(2000)
.withWriteTimeoutMillis(2000)
.withHostAndPort(HostAndPort.fromParts(consulHost, 8500)).build();
keyValueClient = consul.keyValueClient();
healthClient = consul.healthClient();
agentClient = consul.agentClient();
// 注册本服务到 consul
registerService(bootService, bootService, bootService, consulHost, port, 5);
// 注册测试 redis 服务
registerService(redisService, redisService, redisService, redisHost, redisPort, 5);
// 获取可用 redis 服务
getHealthService(redisService);
// 监控 redis 服务
watchSvrx();
}
/**
* 注册服务
*/
public void registerService(String svrId, String svrName, String tags, String host, Integer port, Integer interval){
// 健康检查
ImmutableRegCheck immutableRegCheck = ImmutableRegCheck.builder().tcp(host + ":"+ port).interval(interval +"s").build();
ImmutableRegistration immutableRegistration = ImmutableRegistration.builder().
id(svrId).
name(svrName).
addTags(tags).
address(host).
port(port).
addChecks(immutableRegCheck).
build();
agentClient.register(immutableRegistration);
}
/**
* 获取正常服务
* @param serviceName
*/
public void getHealthService(String serviceName){
List<ServiceHealth> nodes = healthClient.getHealthyServiceInstances(serviceName).getResponse();
dealHealthSvr(nodes);
}
private void dealHealthSvr(List<ServiceHealth> services){
if(StringUtils.isNotBlank(JedisUtils.getHost()) && services.size()> 0) {
services.forEach((resp) -> {
if (StringUtils.equals(resp.getService().getAddress(), JedisUtils.getHost()) &&
resp.getService().getPort() == JedisUtils.getPort()) {
if(JedisUtils.getJedisPool().isClosed()){
JedisUtils.init(resp.getService().getAddress(), resp.getService().getPort());
return;
}
return;
}
});
}
if(StringUtils.isBlank(JedisUtils.getHost()) && services.size()> 0) {
services.forEach((resp) -> {
Service service = resp.getService();
System.out.println("service port: " + service.getPort());
System.out.println("service address: " + service.getAddress());
// 选取一个服务器初始化 redis jedispool
if (JedisUtils.init(service.getAddress(), service.getPort())) {
return;
}
});
}
if(JedisUtils.getJedisPool() != null) {
// 测试 redis
JedisUtils.set("test key","test value");
JedisUtils.get("test key");
// 测试 redis 分布式锁
JedisUtils.setLockKey("test lock key","test lock value", 3);
JedisUtils.get("test lock key");
}
}
// 监控 redis 可用服务
ScheduledExecutorService scheduled = Executors.newSingleThreadScheduledExecutor();
public void watchSvrx(){
scheduled.scheduleAtFixedRate(new Runnable() {
@Override
public void run() {
getHealthService(redisService);
}
}, 0, 10, TimeUnit.SECONDS);
}
public void watchSvr(){
try {
ServiceHealthCache serviceHealthCache = ServiceHealthCache
.newCache(healthClient, redisService);
serviceHealthCache.addListener(map -> {
logger.info("ServiceHealthCache change event");
List<ServiceHealth> list = new ArrayList<ServiceHealth>();
for (ServiceHealth serviceHealth : map.values()) {
list.add(serviceHealth);
}
ConsulMgr.this.dealHealthSvr(list);
});
serviceHealthCache.start();
} catch (Exception e) {
logger.info("ServiceHealthCache e: {}", e);
}
}
}
九、reids 分布式锁
public class JedisUtils {
private static final Logger logger = LoggerFactory.getLogger(JedisUtils.class);
// 设置锁的 lua 脚本
private static final String SETNX_EXPIRE_SCRIPT = "if redis.call('setnx', KEYS[1], KEYS[2]) == 1 then\n"
+ "return redis.call('expire', KEYS[1], KEYS[3]);\n"+"end\n"+"return nil;";
private static JedisPool jedisPool;
public static JedisPool getJedisPool() {
return jedisPool;
}
public static void setJedisPool(JedisPool jedisPool) {
JedisUtils.jedisPool = jedisPool;
}
private static String host;
private static Integer port;
public static String getHost() {
return host;
}
public static void setHost(String host) {
JedisUtils.host = host;
}
public static Integer getPort() {
return port;
}
public static void setPort(Integer port) {
JedisUtils.port = port;
}
public static boolean init(String host, Integer port){
try {
JedisUtils.host = host;
JedisUtils.port = port;
jedisPool = new JedisPool(host, port);
System.out.println(jedisPool);
return true;
}catch (Exception e){}
return false;
}
public static boolean checkExist(String key) {
if(jedisPool == null) return false;
try (Jedis jedis = jedisPool.getResource()) {
logger.info("get redis key record: {}", jedis.get(key));
return jedis.exists(key);
}catch (Exception e) {
logger.warn("get redis key record failed , the message is " + e.getMessage());
}
return false;
}
public static void set(String key, String value) {
if(jedisPool == null) return;
try (Jedis jedis = jedisPool.getResource()) {
logger.info("set key: {}, value: {}", key, value);
jedis.set(key, value);
jedis.expire(key, 20);
}catch (Exception e) {
logger.warn("set key failed , the message is " + e.getMessage());
}
}
public static String get(String key) {
if(jedisPool == null) return null;
try (Jedis jedis = jedisPool.getResource()) {
String value = jedis.get(key);
logger.info("get key: {}, value: {}", key, value);
return value;
}catch (Exception e) {
logger.warn("get key failed , the message is " + e.getMessage());
}
return null;
}
/**
* 设置锁的 lua 脚本
* private static final String SETNX_EXPIRE_SCRIPT = "if redis.call('setnx', KEYS[1], KEYS[2]) == 1 then\n"
* "return redis.call('expire', KEYS[1], KEYS[3]);\n" + "end\n" + "return nil;";
*
* @param key
* @return
*/
public static boolean setLockKey(String key, String value, Integer seconds) {
if (jedisPool == null) return false;
try (Jedis jedis = jedisPool.getResource()) {
if(jedis.eval(SETNX_EXPIRE_SCRIPT, 3, key, value, String.valueOf(seconds)) != null){
logger.info("set lock key: {}, value: {}", key, value);
return true;
}
}catch (Exception e) {
logger.warn("set lock key failed , the message is " + e.getMessage());
}
return false;
}
}
十、SPI 机制
参考:Java SPI 机制
十一、static 资源
配置个性化资源路径:
@Configuration
public class WebMvcConfigurer extends WebMvcConfigurerAdapter {
@Override
public void addResourceHandlers(ResourceHandlerRegistry registry) {
registry.addResourceHandler("/uploadImg/**").addResourceLocations("file:/data/share/plane_images/");
super.addResourceHandlers(registry);
}
十二、druid 数据源
package org.windwant.spring.config;
import com.alibaba.druid.support.http.StatViewServlet;
import com.alibaba.druid.support.http.WebStatFilter;
import com.alibaba.druid.support.spring.stat.BeanTypeAutoProxyCreator;
import com.alibaba.druid.support.spring.stat.DruidStatInterceptor;
import org.springframework.aop.framework.ProxyFactoryBean;
import org.springframework.aop.support.DefaultPointcutAdvisor;
import org.springframework.aop.support.JdkRegexpMethodPointcut;
import org.springframework.boot.web.servlet.FilterRegistrationBean;
import org.springframework.boot.web.servlet.ServletRegistrationBean;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.windwant.spring.service.BootService;
import java.util.Arrays;
/**
* Created by Administrator on 2018/2/6.
*/
@Configuration
public class DruidConfig {
/**
* 注册 StatViewServlet druid web 页面使用
* @return
*/
@Bean
public ServletRegistrationBean druidServlet() {
ServletRegistrationBean reg = new ServletRegistrationBean();
reg.setServlet(new StatViewServlet());
reg.addUrlMappings("/druid/*");
return reg;
}
@Bean
public FilterRegistrationBean druidWebStatFilter(){
FilterRegistrationBean reg = new FilterRegistrationBean();
reg.setFilter(new WebStatFilter());
reg.setUrlPatterns(Arrays.asList("/*"));
reg.addInitParameter("exclusions","*.js,*.gif,*.jpg,*.png,*.css,*.ico,/druid/*");
reg.addInitParameter("sessionStatMaxCount","1000");
reg.addInitParameter("sessionStatEnable","true");
reg.addInitParameter("principalSessionName","druid.user");
reg.addInitParameter("profileEnable","true");
return reg;
}
/**
* Spring 和 Jdbc 的关联监控。
* DruidStatInterceptor: 标准的 Spring MethodInterceptor。可以灵活进行 AOP 配置
* Advice
* @return
*/
@Bean
public DruidStatInterceptor interceptorNames(){
DruidStatInterceptor inc = new DruidStatInterceptor();
return inc;
}
//===================== 按类型拦截 配置 Spring 监控 ============================================
/**
* 按类型拦截配置
* @return
*/
@Bean
public BeanTypeAutoProxyCreator beanTypeAutoProxyCreator(){
BeanTypeAutoProxyCreator cut = new BeanTypeAutoProxyCreator();
cut.setTargetBeanType(BootService.class);
cut.setInterceptorNames("interceptorNames");
return cut;
}
//===================== 按方法名正则匹配拦截 配置 Spring 监控 ====================================
/**
* pointcut
* @return
*/
@Bean
public JdkRegexpMethodPointcut jdkRegexpMethodPointcut(){
JdkRegexpMethodPointcut cut = new JdkRegexpMethodPointcut();
cut.setPatterns("org.windwant.spring.mapper.*");
return cut;
}
/**
* Advisor
* @param pointcut
* @param interceptor
* @return
*/
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor(JdkRegexpMethodPointcut pointcut, DruidStatInterceptor interceptor){
DefaultPointcutAdvisor advisor = new DefaultPointcutAdvisor();
advisor.setPointcut(pointcut);
advisor.setAdvice(interceptor);
return advisor;
}
/**
* AOP proxy based on beans in Spring
* @return
*/
@Bean
public ProxyFactoryBean proxyFactoryBean(){
ProxyFactoryBean proxy = new ProxyFactoryBean();
proxy.setInterceptorNames("defaultPointcutAdvisor");
return proxy;
}
}
十三、dubbo rpc
<?xml version="1.0"encoding="UTF-8"?>
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:dubbo="http://code.alibabatech.com/schema/dubbo"
xmlns:context="http://www.springframework.org/schema/context"
xmlns="http://www.springframework.org/schema/beans"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://code.alibabatech.com/schema/dubbo
http://code.alibabatech.com/schema/dubbo/dubbo.xsd http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd">
<context:property-placeholder location="classpath:application.yml"/>
<dubbo:application name="${dubbo.application.name}"owner="boot-server"
organization="windwant"/>
<dubbo:registry id="bootRegistry"address="${dubbo.registry.address}"/>
<dubbo:protocol port="${dubbo.protocal.port}"serialization="${dubbo.protocal.serialization}"
dispatcher="all"optimizer="org.windwant.common.api.SerializationOptimizerImpl"
threadpool="cached"threads="${dubbo.provider.threads}"/>
<dubbo:protocol id="publicApi"port="${dubbo.protocal.port}"serialization="${dubbo.protocal.serialization}"
dispatcher="all"threadpool="cached"threads="${dubbo.provider.threads}"/>
<dubbo:provider timeout="${dubbo.provider.timeout}" filter="dubboCatFilter"
proxy="${dubbo.provider.proxy}"retries="${dubbo.provider.retries}"/>
<dubbo:service interface="org.windwant.common.api.DubboService"ref="dubbosvr"
registry="bootRegistry"/>
</beans>
。。。
Spring Boot 官网:https://projects.spring.io/spring-boot/