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: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验证提示信息:
@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", "");
        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/

Spring boot 基于Spring MVC的Web应用和REST服务开发的更多相关文章

  1. Spring Boot 基于Spring Initializer 的快速构建 day02

    一.基于Spring Initializr 快速构建Spring Boot项目(快速) 备注:需要联网 这是使用Intellij Idea快速构建可以为我们省去大量的pom.xml配置时间,简单操作, ...

  2. 如何优雅的关闭基于Spring Boot 内嵌 Tomcat 的 Web 应用

    背景 最近在搞云化项目的启动脚本,觉得以往kill方式关闭服务项目太粗暴了,这种kill关闭应用的方式会让当前应用将所有处理中的请求丢弃,响应失败.这种形式的响应失败在处理重要业务逻辑中是要极力避免的 ...

  3. 基于Spring Boot、Spring Cloud、Docker的微服务系统架构实践

    由于最近公司业务需要,需要搭建基于Spring Cloud的微服务系统.遍访各大搜索引擎,发现国内资料少之又少,也难怪,国内Dubbo正统治着天下.但是,一个技术总有它的瓶颈,Dubbo也有它捉襟见肘 ...

  4. spring boot与spring mvc的区别是什么?

    Spring 框架就像一个家族,有众多衍生产品例如 boot.security.jpa等等.但他们的基础都是Spring 的 ioc和 aop ioc 提供了依赖注入的容器 aop ,解决了面向横切面 ...

  5. spring boot与spring mvc的区别

    Spring 框架就像一个家族,有众多衍生产品例如 boot.security.jpa等等.但他们的基础都是Spring 的 ioc和 aop ioc 提供了依赖注入的容器 aop ,解决了面向横切面 ...

  6. 基于Spring Boot和Spring Cloud实现微服务架构学习

    转载自:http://blog.csdn.net/enweitech/article/details/52582918 看了几周Spring相关框架的书籍和官方demo,是时候开始总结下这中间的学习感 ...

  7. 基于Spring Boot和Spring Cloud实现微服务架构学习--转

    原文地址:http://blog.csdn.net/enweitech/article/details/52582918 看了几周spring相关框架的书籍和官方demo,是时候开始总结下这中间的学习 ...

  8. 基于Spring Boot和Spring Cloud实现微服务架构

    官网的技术导读真的描述的很详细,虽然对于我们看英文很费劲,但如果英文不是很差,请选择沉下心去读,你一定能收获好多.我的学习是先从Spring boot开始的,然后接触到微服务架构,当然,这一切最大的启 ...

  9. Spring、Spring Boot、Spring Frame、Spring MVC的区别

    Spring框架就像一个厂商,其下有很多产品,如Spring Boot.Spring Frame.Spring Cloud等等. Spring Boot用于快速.方便.简单的搭建一个Spring项目. ...

随机推荐

  1. 在Win Server 2012中安装.NET Framework 3.5的问题

    在Windows Server 2012 上安装 SQL Server 2012 时,提示 启用 Windows 功能 NetFx3 时出错,错误代码:-2146498298.请尝试从 Windows ...

  2. 【Java每日一题】20161109

    package Nov2016; import java.lang.reflect.Method; public class Ques1109 { public static void main(St ...

  3. Principal Data Scientist

    http://stackoverflow.com/jobs/124781/principal-data-scientist-concur-technologies-inc?med=clc&re ...

  4. loadrunner用javavuser进行接口测试

    在日常工作中会遇到被测试系统通讯都是通过加密的数据包,加密算法是公司自己开发的,并且发送的数据包还要经过系统的压缩,以保证系统的性能.利用loadrunner就无法解决这里的加密的技术问题,利用jav ...

  5. Java程序运行时,数据都保存到什么地方?

    程序运行时,我们最好对数据保存到什么地方做到心中有数.特别要注意的是内存的分配.有六个地方都可以保存数据: 寄存器 这是最快的保存区域,因为它位于和其他所有保存方式不同的地方:处理器内部.然而,寄存器 ...

  6. angular学习的一些小笔记(中)之ng-disabled轻松实现按钮是否可点击状态

    哇,这个可以轻松实现输入值就按钮可点击,输入框没有值则不可点击的状态呀 看代码 <!doctype html> <html ng-app=""> <h ...

  7. 调用MyFocus库,简单实现二十几种轮播效果

    一.首先点击这里下载myFocus库文件,标准文件库就行了,很小仅仅1.4M. myFocus库有以下的好处: a . 文件小巧却高效强大,能够实现二十几种轮播的效果. b . 极其简单的使用,只需要 ...

  8. JS与一般处理程序之间传值乱码

    好久没用到,突然遇到此问题还用了点时间. 在JS里面通过URL向Handler传中文值的时候,在Handler里面取值出来后会发现是乱码的~~.这就需要个编码解码过程.(先记录自己遇到的一个方面的解决 ...

  9. SAP打印机配置

    SAP打印机配置 一.SAP打印原理 SAP的打印过程分两个步骤: 1.创建假脱机请求: 2.创建输出请求: 在点击打印按钮后,系统会提示创建假脱机请求后,你可以选择直接生成输出请求,或者手动生成输出 ...

  10. inputType属性

    android中inputType属性在EditText输入值时启动的虚拟键盘的风格有着重要的作用.这也大大的方便的操作.有时需要虚拟键盘只为字符或只为数字.所以inputType尤为重要.<E ...