
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方法。
@Configurationpublic class ApplicationConfig {    @Configuration    public class WebMvcConfigurer extends WebMvcConfigurerAdapter {        public void addInterceptors(InterceptorRegistry registry) {            registry.addInterceptor(new BootInterceptor()).addPathPatterns("/**");            super.addInterceptors(registry);        }...3. listenenr:实现各种listener@WebListenerpublic 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: trueDataSource 注解配置:
/** * Created by windwant on 2016/12/30. * implements EnvironmentAware, ApplicationContextAware */@Configurationpublic 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配置:
@Beanpublic 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 @Componentpublic class BootJob {    private static final SimpleDateFormat dateFormat = new SimpleDateFormat("HH:mm: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验证提示信息:@Beanpublic 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 addCorsMappingsaddMapping:请求拦截allowedOrigins:拦截请求源allowedMethods:拦截方法@Configurationpublic 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权限配置@Configurationpublic 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. */@Componentpublic 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资源配置个性化资源路径:@Configurationpublic 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. */@Configurationpublic 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/