一:什么是ACL和RBAC:

ACL: Access Control List 访问控制列表
  以前盛行的一种权限设计,它的核心在于用户直接和权限挂钩
  优点:简单易用,开发便捷
  缺点:用户和权限直接挂钩,导致在授予时的复杂性,比较分散,不便于管理
  例子:常见的文件系统权限设计, 直接给用户加权限
RBAC: Role Based Access Control
  基于角色的访问控制系统。权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限
  优点:简化了用户与权限的管理,通过对用户进行分类,使得角色与权限关联起来
  缺点:开发对比ACL相对复杂
  例子:基于RBAC模型的权限验证框架与应用 Apache Shiro、spring Security
  BAT企业 ACL,一般是对报表系统,阿里的ODPS

总结:不能过于复杂,规则过多,维护性和性能会下降, 更多分类 ABAC、PBAC等

二:Apache Shiro基础知识和架构

Shiro是一个强大易用的Java安全框架,提供了认证、授权、加密和会话管理等功能

shiro包含四大核心模块:身份认证,授权,会话管理和加密

直达Apache Shiro官网 http://shiro.apache.org/introduction.html
什么是身份认证
  Authentication,身份证认证,一般就是登录
什么是授权
  Authorization,给用户分配角色或者访问某些资源的权限
什么是会话管理
  Session Management, 用户的会话管理员,多数情况下是web session
什么是加密
  Cryptography, 数据加解密,比如密码加解密等

shiro架构图

三.用户访问Shiro权限控制运行流程

Subject
  我们把用户或者程序称为主体(如用户,第三方服务,cron作业),主体去访问系统或者资源
SecurityManager
  安全管理器,Subject的认证和授权都要在安全管理器下进行
Authenticator
  认证器,主要负责Subject的认证
Realm
  数据域,Shiro和安全数据的连接器,好比jdbc连接数据库; 通过realm获取认证授权相关信息
Authorizer
  授权器,主要负责Subject的授权, 控制subject拥有的角色或者权限
Cryptography
  加解密,Shiro的包含易于使用和理解的数据加解密方法,简化了很多复杂的api
Cache Manager
  缓存管理器,比如认证或授权信息,通过缓存进行管理,提高性能

四.Springboot2.x整合Apache Shiro实战

项目环境:

  Maven3.5 + Jdk8 + Springboot 2.X + IDEA

相关依赖

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>

<dependency>
<groupId>org.mybatis.spring.boot</groupId>
<artifactId>mybatis-spring-boot-starter</artifactId>
<version>2.0.1</version>
</dependency>

<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<!--注释掉-->
<!--<scope>runtime</scope>-->
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>

<!--阿里巴巴druid数据源-->
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>druid</artifactId>
<version>1.1.6</version>
</dependency>

<!--spring整合shiro-->
<dependency>
<groupId>org.apache.shiro</groupId>
<artifactId>shiro-spring</artifactId>
<version>1.4.0</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.16.16</version>
</dependency>

<!-- shiro+redis缓存插件 主要用于CacheManager,以及缓存sessionManage中配置session持久化-->
<dependency>
<groupId>org.crazycake</groupId>
<artifactId>shiro-redis</artifactId>
<version>3.1.0</version>
</dependency>

Shiro各个组件说明

Realm:

realm作用:Shiro 从 Realm 获取安全数据
  默认自带的realm:idae查看realm继承关系,有默认实现和自定义继承的realm
两个概念
  principal : 主体的标示,可以有多个,但是需要具有唯一性,常见的有用户名,手机号,邮箱等
  credential:凭证, 一般就是密码
  所以一般我们说 principal + credential 就账号 + 密码
开发中,往往是自定义realm , 即继承 AuthorizingRealm,重写doGetAuthenticationInfo(认证方法)和doGetAuthorizationInfo(授权方法)

当用户登陆的时候会调用 doGetAuthenticationInfo
进行权限校验的时候会调用: doGetAuthorizationInfo

UsernamePasswordToken : 对应就是 shiro的token中有Principal和Credential
  UsernamePasswordToken-》HostAuthenticationToken-》AuthenticationToken
SimpleAuthorizationInfo:代表用户角色权限信息
SimpleAuthenticationInfo :代表该用户的认证信息

Shiro内置的Filter

核心过滤器类:DefaultFilter, 配置哪个路径对应哪个拦截器进行处理
authc:org.apache.shiro.web.filter.authc.FormAuthenticationFilter
  需要认证登录才能访问
user:org.apache.shiro.web.filter.authc.UserFilter
  用户拦截器,表示必须存在用户。
anon:org.apache.shiro.web.filter.authc.AnonymousFilter
  匿名拦截器,不需要登录即可访问的资源,匿名用户或游客,一般用于过滤静态资源。
roles:org.apache.shiro.web.filter.authz.RolesAuthorizationFilter
  角色授权拦截器,验证用户是或否拥有角色。
  参数可写多个,表示某些角色才能通过,多个参数时写 roles["admin,user"],当有多个参数时必须每个
  参数都通过才算通过
perms:org.apache.shiro.web.filter.authz.PermissionsAuthorizationFilter
  权限授权拦截器,验证用户是否拥有权限
  参数可写多个,表示需要某些权限才能通过,多个参数时写 perms["user, admin"],当有多个参数时必
  须每个参数都通过才算可以

authcBasic:org.apache.shiro.web.filter.authc.BasicHttpAuthenticationFilter
  httpBasic 身份验证拦截器。
logout:org.apache.shiro.web.filter.authc.LogoutFilter
  退出拦截器,执行后会直接跳转到shiroFilterFactoryBean.setLoginUrl(); 设置的 url
port:org.apache.shiro.web.filter.authz.PortFilter
  端口拦截器, 可通过的端口。
ssl:org.apache.shiro.web.filter.authz.SslFilter
  ssl拦截器,只有请求协议是https才能通过。

  Filter的配置路径说明:

  /admin/video /user /pub
  路径通配符支持 ?、*、**,注意通配符匹配不 包括目录分隔符“/”
  心 可以匹配所有,不加*可以进行前缀匹配,但多个冒号就需要多个 * 来匹配
  URL权限采取第一次匹配优先的方式
    ? : 匹配一个字符,如 /user? , 匹配 /user3,但不匹配/user/;
    * : 匹配零个或多个字符串,如 /add* ,匹配 /addtest,但不匹配 /user/1
    ** : 匹配路径中的零个或多个路径,如 /user/** 将匹 配 /user/xxx 或 /user/xxx/yyy
  例子
  /user/**=filter1
  /user/add=filter2
  请求 /user/add 命中的是filter1拦截器
  性能问题:通配符比字符串匹配会复杂点,所以性能也会稍弱,推荐是使用字符串匹配方式

数据加解密器CredentialsMatche 

一般会自定义验证规则
  @Bean
  public HashedCredentialsMatcher hashedCredentialsMatcher(){
    HashedCredentialsMatcher hashedCredentialsMatcher = new
    HashedCredentialsMatcher();
    //散列算法,使用MD5算法;
    hashedCredentialsMatcher.setHashAlgorithmName("md5");
    //散列的次数,比如散列两次,相当于 md5(md5("xxx"));
    hashedCredentialsMatcher.setHashIterations(2);
    return hashedCredentialsMatcher;
}

Shiro的缓存模块CacheManager

  shiro中提供了对认证信息和授权信息的缓存。

  默认是关闭认证信息缓存的,对于授权信息的缓存shiro默认开启的(因为授权的数据量大,每次都要查询数据库,性能受到影响)
  AuthenticatingRealm 及 AuthorizingRealm 分别提供了对AuthenticationInfo 和 AuthorizationInfo 信息的缓
存。

Shiro中的SessionManager

  用户和程序直接的链接,程序可以根据session识别到哪个用户,和javaweb中的session类似

  什么是会话管理器SessionManager
    会话管理器管理所有subject的所有操作,是shiro的核心组件,前后端分离的应用中session通常用token代替,用于会话管理

RBAC权限控制架构设计

  1.数据库设计:老五张表

    用户,角色,权限,用户角色表,角色权限表

  2.shiro相关配置

    -配置ShiroFilterFactoryBean   

      配置流程和思路
      shiroFilterFactoryBean-》
        -SecurityManager-》
          -CustomSessionManager
          -CustomRealm-》hashedCredentialsMatcher
      SessionManager
        -DefaultSessionManager: 默认实现,常用于javase
        -ServletContainerSessionManager: web环境
        -DefaultWebSessionManager:常用于自定义实现(一般用这种)

ShiroConfig配置

@Configuration
public class ShiroConfig { /**
* 配置ShiroFilterFactoryBean
*
* @param securityManager
* @return
*/
@Bean
public ShiroFilterFactoryBean shiroFilter(SecurityManager securityManager) { System.out.println("执行 ShiroFilterFactoryBean shiroFilter");
ShiroFilterFactoryBean shiroFilterFactoryBean = new ShiroFilterFactoryBean(); //必须设置securityManager
shiroFilterFactoryBean.setSecurityManager(securityManager); //需要登录的接口:如果访问某个接口,需要登录却没有登录,则调用此接口,如果前端后端不分离,则跳转到html页面
shiroFilterFactoryBean.setLoginUrl("/pub/need_login"); //登录成功 跳转url,如果前后端分离,则没这个调用 --这里设置为首页就行了
shiroFilterFactoryBean.setSuccessUrl("/"); //登录成功,但是没有权限,未授权就会调用这个接口,如果不是前后端分离,则跳转到403页面
shiroFilterFactoryBean.setUnauthorizedUrl("/pub/not_permit"); //设置自定义filter
Map<String, Filter> filterMap = new LinkedHashMap<>();
filterMap.put("roleOrFilter", new CustomRoleFilter()); //shiroFilterFactoryBean绑定自定义的filter
shiroFilterFactoryBean.setFilters(filterMap); //过滤器链的map
//拦截器(过滤器路径,坑一必须要用LinkedhashMap),部分路径无法进行拦截
Map<String, String> filterChainDefinitionMap = new LinkedHashMap<>(); /*
********************************************
通常是配置这些过滤器,也可以用个数据库的动态加载,这些数据
********************************************/
//退出过滤器
filterChainDefinitionMap.put("/logout", "logout"); //匿名可以访问,也就是游客模式
filterChainDefinitionMap.put("/pub/**", "anon"); //登录用户才可以访问
filterChainDefinitionMap.put("/authc/**", "authc"); //管理员角色才可以访问
filterChainDefinitionMap.put("/admin/**", "roles[admin]"); //有编辑权限才可以访问
filterChainDefinitionMap.put("/video/update", "perms[video_update]"); //坑二:过滤器是顺序执行,从上而下,一般来说/** 放到最下面 //authc: url定义必须通过认证才可以访问
//anno: url可以匿名访问
filterChainDefinitionMap.put("/**", "authc"); //配置过滤器
shiroFilterFactoryBean.setFilterChainDefinitionMap(filterChainDefinitionMap); return shiroFilterFactoryBean;
} /**
* 数据域
*
* @return
*/
@Bean
public CustomRealm customRealm() { CustomRealm customRealm = new CustomRealm(); //设置加密器--因为数据库中的密码不是明文存储
customRealm.setCredentialsMatcher(hashedCredentialsMatcher());
return customRealm;
}
/**
* 自定义seesionManager
* -配置session持久化
* @return
*/
@Bean
public SessionManager sessionManager() {
//自定义CustomSessionManager 继承 DefaultWebSessionManager
CustomSessionManager customSessionManager = new CustomSessionManager(); //配置session持久化
customSessionManager.setSessionDAO(redisSessionDAO()); //超时时间,默认 30分钟,会话超时;方法里面的单位是毫秒
customSessionManager.setGlobalSessionTimeout(20000); return customSessionManager;
} /**
* 密码加解密规则 CredentialMatcher-配置在数据域中,用于数据的加解密
*
* @return
*/
@Bean
public HashedCredentialsMatcher hashedCredentialsMatcher() {
HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher(); //设置散列算法:这里使用MD5算法
hashedCredentialsMatcher.setHashAlgorithmName("md5"); //散列次数,好比散列两次 相当于md5(md5(x))
hashedCredentialsMatcher.setHashIterations(2); return hashedCredentialsMatcher;
}
/**
* 配置redisManager
*/
@Bean
public RedisManager getRedisManager() { RedisManager redisManager = new RedisManager(); //默认就是localhost:6379 不写也行
redisManager.setHost("localhost");
redisManager.setPort(6379);
return redisManager;
}
/**
* 配置具体cache实现类RedisCacheManager
* 为什么要使用缓存:
* 缓存组件位于SecurityManager中,在CustomRealm数据域中,由于授权方法中每次都要查询数据库,性能受影响,因此将数据缓存起来,提高查询效率
* 除了使用Redis缓存,还能使用shiro-ehcache
*
* @return
*/
public RedisCacheManager redisCacheManager() {
RedisCacheManager redisCacheManager = new RedisCacheManager();
redisCacheManager.setRedisManager(getRedisManager());
//设置过期时间,单位是秒,20s,
redisCacheManager.setExpire(20);
return redisCacheManager;
}
/**
* 自定义session持久化
*
* @return
*/
public RedisSessionDAO redisSessionDAO() { /*
为啥session也要持久化?
重启应用,用户无感知,可以继续以原先的状态继续访问
注意点:
DO对象需要实现序列化接口 Serializable
logout接口和以前一样调用,请求logout后会删除redis里面的对应的key,即删除对应的token
*/
RedisSessionDAO redisSessionDAO = new RedisSessionDAO();
redisSessionDAO.setRedisManager(getRedisManager()); //配置自定义sessionId,shiro自动生成色sessionId不满足条件时可以使用
redisSessionDAO.setSessionIdGenerator(new CustomSessionIdGenerator());
return redisSessionDAO;
}
/**
* LifecycleBeanPostProcessor
* 管理shiro一些bean的生命周期 即bean初始化 与销毁
*
* @return
*/
@Bean
public LifecycleBeanPostProcessor lifecycleBeanPostProcessor() {
return new LifecycleBeanPostProcessor();
} /**
* AuthorizationAttributeSourceAdvisor
* 作用:加入shiro注解的使用,不加入这个AOP注解不生效(shiro的注解 例如 @RequiresGuest)
*/
@Bean
public AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor() {
AuthorizationAttributeSourceAdvisor authorizationAttributeSourceAdvisor = new
AuthorizationAttributeSourceAdvisor();
authorizationAttributeSourceAdvisor.setSecurityManager(securityManager());
return authorizationAttributeSourceAdvisor;
} /**
* DefaultAdvisorAutoProxyCreator
* 作用: 用来扫描上下文寻找所有的Advistor(通知器), 将符合条件的Advisor应用到切入点的Bean中,需
* 要在LifecycleBeanPostProcessor创建后才可以创建
*
* @return
*/
@Bean
@DependsOn("lifecycleBeanPostProcessor")
public DefaultAdvisorAutoProxyCreator getDefaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new
DefaultAdvisorAutoProxyCreator();
defaultAdvisorAutoProxyCreator.setUsePrefix(true);
return defaultAdvisorAutoProxyCreator;
}
}

自定义Filter==>>>CustomRoleFilter 

/**
* 自定义Filter
* 问题:为什么要自定义filter:
* 因为配置role[admin,root] ,只有同时满足admin和root才能够访问,显然这是不合理的
* 实际是超级管理员有全部权限
*/
public class CustomRoleFilter extends AuthorizationFilter { @Override
public boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws IOException {
//获取当前访问路径所有角色的集合
Subject subject = getSubject(request, response);
String[] rolesArray = (String[]) mappedValue; //没有角色显示,可以直接访问
if (rolesArray == null || rolesArray.length == 0) {
//no roles specified, so nothing to check - allow access.
return true;
} //当前subject是roles中的任意一个,则有权限访问
Set<String> roles = CollectionUtils.asSet(rolesArray); for (String role : roles) {
if (subject.hasRole(role)) {
return true;
}
}
return subject.hasAllRoles(roles);
}
}

自定义SessionManager:===>>CustomSessionManager

 /** @Discription 自定义SessionMananger 为什么要自定义自定义SessionMananger?
* 原因:
* 因为前后端分离的情况下 不是靠session,而是靠token去交互,因此需要自定义这个sessionId的获取
* 即重写父类的方法(父类是从头中拿sessionId)
*
*/
public class CustomSessionManager extends DefaultWebSessionManager { //这个key 放在请求头中,可以自己定义 ,通常是设置为token或者authorization
private static final String AUTHORIZATION = "token"; public CustomSessionManager() {
super();
} @Override
protected Serializable getSessionId(ServletRequest request, ServletResponse response) {
//将ServletRequest转换成HttpServletRequest
String sessionId = WebUtils.toHttp(request).getHeader(AUTHORIZATION);
if (sessionId != null) {
// request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE, "cookie");
//
// request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId);
// //automatically mark it valid here. If it is invalid, the
// //onUnknownSession method below will be invoked and we'll remove the attribute at that time.
// request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE); request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_SOURCE,
ShiroHttpServletRequest.COOKIE_SESSION_ID_SOURCE);
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID, sessionId); //automatically mark it valid here. If it is invalid, the
//onUnknownSession method below will be invoked and we'll remove the attribute at that time.
request.setAttribute(ShiroHttpServletRequest.REFERENCED_SESSION_ID_IS_VALID, Boolean.TRUE);
return sessionId;
} else {
return super.getSessionId(request, response);
}
}
}

自定义数据域 CustomRealm

**
* 自定义的realm 数据域
*/ public class CustomRealm extends AuthorizingRealm { @Autowired
private UserService userService; /**
* 权限校验的时候会调用
*
* @param principals
* @return
*/
@Override
protected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection principals) {
System.out.println("授权 doGetAuthorizationInfo"); //从token中获取用户信息,token代表用户输入
// String username = (String) principals.getPrimaryPrincipal();
User newUser = (User) principals.getPrimaryPrincipal(); // 使用原因?
// 授权的时候每次都去查询数据库,对于频繁访问的接口,性能和响应速度比较慢,所以使用缓存 //提高性能的方法1-使用redis缓存:
// 将信息放到缓存,例如redis,但是要设置缓存失效时间,因为可能更新数据库了,但是缓存没有更新
//提高性能的方法2-使用shiro-redis集成的缓存:
// shiro-redis的缓存配置在SecurityManager中
User user = userService.findAllUserInfoByUsername(newUser.getUsername()); List<String> stringRoleList = new ArrayList<>();
List<String> stringPermissionList = new ArrayList<>(); List<Role> roleList = user.getRoleList(); for (Role role : roleList) {
stringRoleList.add(role.getName()); List<Permission> permissionList = role.getPermissionList(); for (Permission p : permissionList) {
if (p != null) {
stringPermissionList.add(p.getName());
}
}
}
SimpleAuthorizationInfo simpleAuthorizationInfo = new SimpleAuthorizationInfo(); //将用户对应的角色和权限信息 放到权限器中
simpleAuthorizationInfo.addStringPermissions(stringPermissionList);
simpleAuthorizationInfo.addRoles(stringRoleList); return simpleAuthorizationInfo;
} /**
* 用户登录的时候会调用
*
* @param token
* @return
* @throws AuthenticationException
*/
@Override
protected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {
System.out.println("认证 doGetAuthenticationInfo"); //从token中获取用户信息,token代表用户输入
String username = (String) token.getPrincipal(); User user = userService.findAllUserInfoByUsername(username); //取密码
String password = user.getPassword(); if (password == null || "".equals(password)) {
return null;
} return new SimpleAuthenticationInfo(user, password, this.getClass().getName());
}
} /*
* 原有的问题
class java.lang.String must has getter for field: authCacheKey or id\nWe need a
field to identify this Cache Object in Redis. So you need to defined an id field
which you can get unique id to identify this principal. For example, if you use
UserInfo as Principal class, the id field maybe userId, userName, email, etc. For
example, getUserId(), getUserName(), getEmail(), etc.\nDefault value is
authCacheKey or id, that means your principal object has a method called
\"getAuthCacheKey()\" or \"getId()\""
改造原有的逻辑,修改缓存的唯一key doGetAuthorizationInfo 方法
原有:
String username = (String)principals.getPrimaryPrincipal();
User user = userService.findAllUserInfoByUsername(username);
改为
User newUser = (User)principals.getPrimaryPrincipal();
User user = userService.findAllUserInfoByUsername(newUser.getUsername()); doGetAuthenticationInfo方法
原有:
return new SimpleAuthenticationInfo(username, user.getPassword(),
this.getClass().getName());
改为
return new SimpleAuthenticationInfo(user, user.getPassword(),
this.getClass().getName());
*
*
* */

代码地址:

https://github.com/AlenYang123456/Springboot-Shiro

 

【SpringBoot】SpringBoot2.x整合Shiro(一)的更多相关文章

  1. SpringBoot2.x整合Shiro(一)

    一:什么是ACL和RBAC: ACL: Access Control List 访问控制列表 以前盛行的一种权限设计,它的核心在于用户直接和权限挂钩 优点:简单易用,开发便捷 缺点:用户和权限直接挂钩 ...

  2. SpringBoot 优雅的整合 Shiro

    Apache Shiro是一个功能强大且易于使用的Java安全框架,可执行身份验证,授权,加密和会话管理.借助Shiro易于理解的API,您可以快速轻松地保护任何应用程序 - 从最小的移动应用程序到最 ...

  3. 在 springboot 中如何整合 shiro 应用 ?

     Shiro是Apache下的一个开源项目,我们称之为Apache Shiro. 它是一个很易用与Java项目的的安全框架,提供了认证.授权.加密.会话管理,与spring Security 一样都是 ...

  4. SpringBoot2.0 整合 Shiro 框架,实现用户权限管理

    本文源码:GitHub·点这里 || GitEE·点这里 一.Shiro简介 1.基础概念 Apache Shiro是一个强大且易用的Java安全框架,执行身份验证.授权.密码和会话管理.作为一款安全 ...

  5. SpringBoot2.x整合Shiro出现cors跨域问题(踩坑记录)

    1. Springboot如何跨域? 最简单的方法是: 定义一个配置CorsConfig类即可(是不是简单且无耦合到令人发指) @Configuration public class CorsConf ...

  6. SpringBoot学习:整合shiro(身份认证和权限认证),使用EhCache缓存

    项目下载地址:http://download.csdn.NET/detail/aqsunkai/9805821 (一)在pom.xml中添加依赖: <properties> <shi ...

  7. SpringBoot学习:整合shiro自动登录功能(rememberMe记住我功能)

    首先在shiro配置类中注入rememberMe管理器 /** * cookie对象; * rememberMeCookie()方法是设置Cookie的生成模版,比如cookie的name,cooki ...

  8. SpringBoot学习:整合shiro(rememberMe记住我后自动登录session失效解决办法)

    项目下载地址:http://download.csdn.NET/detail/aqsunkai/9805821 定义一个拦截器,判断用户是通过记住我登录时,查询数据库后台自动登录,同时把用户放入ses ...

  9. SpringBoot学习:整合shiro(验证码功能和登录次数限制功能)

    项目下载地址:http://download.csdn.NET/detail/aqsunkai/9805821 (一)验证码 首先login.jsp里增加了获取验证码图片的标签: <body s ...

随机推荐

  1. Linux ctrl+z挂起的进程恢复与杀死

    Linux系统下,不小心按了ctrl+z命令后,退出了当前进程的执行界面,程序没有结束,只是被挂起了.通过ps命令可以查看进程信息,这里不做详细介绍,可通过jobs命令查看被挂起的进程号 #jobs ...

  2. Synchronized 轻量级锁会自旋?好像并不是这样的。

    本来是在写面霸系列的,写着写着就写到了这一题: Synchronized 原理知道不? 而关于 Synchronized 我去年还专门翻阅 JVM HotSpot 1.8 的源码来研究了一波,那时候我 ...

  3. Java 虚拟机详解

    深入理解JVM 1   Java技术与Java虚拟机 说起Java,人们首先想到的是Java编程语言,然而事实上,Java是一种技术,它由四方面组成: Java编程语言.Java类文件格式.Java虚 ...

  4. C#中事件流程的简单理解

    C#中事件流程的简单理解 C#中事件基于委托,要理解事件要先理解委托,但是现在我还没想好怎么写委托,如果不懂委托可以先找找委托的文章 事件基于委托,为委托提供了一种发布/订阅机制 一上来就是这句话,很 ...

  5. go中waitGroup源码解读

    waitGroup源码刨铣 前言 WaitGroup实现 noCopy state1 Add Wait 总结 参考 waitGroup源码刨铣 前言 学习下waitGroup的实现 本文是在go ve ...

  6. SpringMVC自定义兼容性Handler

    写在前面 看到这篇博客时,默认你知道Spring MVC中handler的作用,及前台请求到响应的的流转. 感谢网上其他大佬博客给我的借鉴,博客地址这里忘记了. 自定义Handler 我有时候会考虑是 ...

  7. BuaacodingT141 microhhh的回城 题解(模拟)

    题目链接 microhhh的回城 解题思路 这题挺有意思的.本来寻思放在\(DS\)第一次练习赛应该不会很难吧,结果愣是卡在数据范围上写不出来. 然后暴力过掉了,但是用了\(1019ms\).感觉可以 ...

  8. android分析之Condition

    Condition的含义是条件变量,其实现依赖于系统,一般都要配合Mutex使用,使用步骤为:给mutex上锁(Lock),调用wait等待"条件"发生,如果没有发生则re-wai ...

  9. java 动态规划解决最大连续子数列和

    很多动态规划算法非常像数学中的递推.我们如果能找到一个合适的递推公式,就能很容易的解决问题.我们用dp[n]表示以第n个数结尾的最大连续子序列的和,这里第n个数必须在子序列中.于是存在以下递推公式: ...

  10. javascript中的Strict模式

    目录 简介 使用Strict mode strict mode的新特性 强制抛出异常 简化变量的使用 简化arguments 让javascript变得更加安全 保留关键字和function的位置 总 ...