您的位置:澳门皇家赌场真人在线 > 皇家赌场游戏 > 聊聊Java进级之并发基础技术,非常完整

聊聊Java进级之并发基础技术,非常完整

发布时间:2019-10-04 15:43编辑:皇家赌场游戏浏览(139)

    初稿连接,侵删

    组合Mybatis分为三种方式,一种是xml配置,一种是注明。作者在此处根本放在xml配置上,因为一旦想用申明的话,提议间接用jpa代替,因为Jpa有更成熟的CRUD接口更利于开辟。笔者在后文中也会把声明情势说知道。

    那是Strtus的开山篇,首若是引进struts框架...为何要引进struts,引进struts的功利是什么样,以及对Struts2贰个简单易行的入门....

    文摘:在事情系统中,线程池框架技艺向来是用来缓和三十二线程并发的一种有效办法。

    图片 1点击图片访谈小编的私有博客

    乍一看,垃圾收罗的做事应当像其名字一模二样——找寻废物并清理垃圾堆。然则谜底恰好相反。GC会追踪依旧活着的目标,然后把剩下的目的标志为垃圾。请牢记那或多或少,然后我们起头研商JVM中达成的GC怎样自动的拓宽内部存款和储蓄器回收。

    大意介绍下流程:

    既然Servlet能够实现的事,大家为啥要用框架呢??

    在JDK中,J.U.C并发包下的ThreadPoolExecutor大旨类是一种基于Executor接口的线程池框架,将任务交给和义务实施解耦设计,个中Executor瑟维斯和其种种达成类提供了那么些有援助的秘技来交付职责并获得职分施行结果,并打包了任务实行的漫天进程。本文将深刻解读并分析以ThreadPoolExecutor为主干的j.u.c包下Executor线程池框架的有的重视源代码,一步步带读者搞明白JDK中线程池框架背后的设计意见和平运动行机制。

    本文翻译自The Java 8 Stream API Tutorial

    大家一开头应该起首解释GC的特征以及基本概念和办法,并不是上来就进去实际的细节中。

    1. 借助于idea完毕mybatis逆向工程
    2. 用xml配置完毕整合
    3. 用cmd命令行完结mybatis逆向工程
    4. 用mapping.xml配置完成数量交互
    5. 用注脚的方法达成数据交互
    • 框架帮大家封装了好多常用的功效
      • 把Web带过来的参数自动封装到JavaBean中[先前,我们刚开始学的时候是单个单个来获得参数的,后来我们又选择了BeanUtils写工具方法来帮大家封装]。未来,大家选拔了Struts2的话,那么框架之中就能够帮大家封装了。
    • 更为灵活[无须把门路等消息写死在前后相继上],对于路线我们利用安排文件来开展田间管理,假设目录产生了更动,也休想一个贰个去修改每一个程序的路径。
    • 各样Servlet中都有doGet和doPost那样的不二秘诀,没供给的。我们抽出出来,通过布置文件来把那多少个章程替换掉,那么大家的次序就能进一步高雅了。

    友善在接触线程池本领从前,“一向以为在Java中有线程Thread对象,在事情须要的时候不断地创造线程出来不等同也能满意必要么?”,若是我们跟自家下面的那么些主张同样,无妨先来看下如下的开始和结果。

    本教程志在条分缕析入微、深远底层,你将体验从Stream的创办起来到并行推行(parallel execution)的完全经过,以此体会Stream API的其实用处。

    在我们早先批评GC在此之前,先想起一下事先的内部存款和储蓄器管理。大家必须为顺序手动的分配内部存款和储蓄器,并在毫不的时候释放掉该内部存款和储蓄器。假若程序中忘记释放那块内部存款和储蓄器,大家就不能够再一次行使那块内部存款和储蓄器。内部存款和储蓄器被申请却从未被运用,这种地方就是内存泄漏下边是三个C语言完成的手动内部存储器管理的例证

    率先我的支出条件:jdk1.8+maven3+IDEA

    于是乎,struts2就涌出了。

    在劳务器端的专门的工作使用开垦中,Web服务器(诸如汤姆cat、Jetty)需求接受并拍卖http乞求,所以会为三个呼吁来分配贰个线程来打开管理。倘使老是诉求都新创造三个线程的话达成起来非常方便,但是存在这么的不得了难点:

    为了知道上面包车型大巴篇章,读者供给驾驭Java 7基础知识(Lambda表明式、Optional、方法引用)以及熟习Stream API,如若您并不理解它们以至一窍不通,建议你先读书我们事先的稿子-Java8 新特色 以及 Java 8 Streams 介绍。

    int send_request() { size_t n = read_size(); int *elements = malloc(n * sizeof; if(read_elements(n, elements) < n) { // elements not freed! return -1; } // … free return 0;}
    

    1. mybatis逆向攻城

    逆向工程措施非常多,笔者当下触及到的就二种,一种是依附ide开垦工具,一种是在cmd中试行命令。(其实双方原理都一致,都是推行maven的generator命令,具体请看下文)。

    在规范上课struts以前,大家来看一下,以大家前几日的水准,能够怎么优化它。。

    乘胜业务量的加码,假使出现的呼吁数量相当多,但每一个线程施行的小运异常的短,那样就能够屡次的创制和销毁线程(包含涉嫌JVM的GC),如此一来会大大收缩业务种类的频率。大概出现服务器在为各种乞求成立新线程和销毁线程上海消防费的时间和消耗的系统财富要比拍卖实际的客商央浼的时日和财富更多。

    成立两个Stream实例有多样方法,各种创造格局对应Stream的三个起点。但单个Stream实例每便创制之后,其根源将不可能修改,那意味着Stream实例具有源头不可变性,可是大家却能够从单个源创设多个Stream实例。

    正如小编辈所见,大家很轻易就能够忘记释放无用的内部存款和储蓄器。而产出这种内部存储器泄漏,大家不得不通过修改代码的格局修复难题。由此,更加好的方法是机动的回收不利用的内部存款和储蓄器。这种自发性回收内部存款和储蓄器的法子就是Garbag Collection

    1. 完善pom文件
    <?xml version="1.0" encoding="UTF-8"?><project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>springboot-mybatis</groupId> <artifactId>springboot-mybatis</artifactId> <version>0.0.1-SNAPSHOT</version> <packaging>jar</packaging> <name>springboot-mybatis</name> <description>Demo project for Spring Boot</description> <parent> <groupId>springboot-integration</groupId> <artifactId>springboot-integration</artifactId> <version>1.0-SNAPSHOT</version> </parent> <!-- Add typical dependencies for a web application --> <dependencies> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-jdbc</artifactId> </dependency> <dependency> <groupId>org.mybatis.spring.boot</groupId> <artifactId>mybatis-spring-boot-starter</artifactId> <version>1.3.0</version> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-thymeleaf</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-web</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-test</artifactId> <scope>test</scope> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.35</version> </dependency> <!-- alibaba的druid数据库连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.0.11</version> </dependency> <!-- alibaba的druid数据库连接池 --> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid-spring-boot-starter</artifactId> <version>1.1.0</version> </dependency> <dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <scope>test</scope> </dependency> <!-- 分页插件 --> <dependency> <groupId>com.github.pagehelper</groupId> <artifactId>pagehelper</artifactId> <version>5.0.4</version> </dependency> </dependencies> <!-- Package as an executable jar --> <build> <finalName>springboot-mybatis</finalName> <plugins> <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-surefire-plugin</artifactId> <configuration> <testFailureIgnore>true</testFailureIgnore> </configuration> </plugin> <plugin> <groupId>org.mybatis.generator</groupId> <artifactId>mybatis-generator-maven-plugin</artifactId> <version>1.3.2</version> <configuration> <verbose>true</verbose> <overwrite>true</overwrite> </configuration> </plugin> </plugins> </build></project>
    

    以顾客的登入注册案例来实行求证

    那么有未有一种减轻方案能够使线程在推行完四个职责后,不被销毁,而是能够继续实践其余的任务吗?

    方法empty()被用来创立一个Empty Stream:

    机动回收内部存储器的第二个方式正是使用析构器。如下例子,大家得以行使C++中的vector,当vector对象不在成效域的时候,它的析构函数会自动调用进行内存回收。

    2. 逆向所需布置文件generatorConfig.xml
    <?xml version="1.0" encoding="UTF-8"?><!DOCTYPE generatorConfiguration PUBLIC "-//mybatis.org//DTD MyBatis Generator Configuration 1.0//EN" "http://mybatis.org/dtd/mybatis-generator-config_1_0.dtd"><generatorConfiguration> <!-- 数据库驱动:选择你的本地硬盘上面的数据库驱动包--> <classPathEntry location="E:libmysql_drivermysql-connector-java-5.1.26-bin.jar"/> <context targetRuntime="MyBatis3"> <commentGenerator> <property name="suppressDate" value="true"/> <!-- 是否去除自动生成的注释 true:是 : false:否 --> <property name="suppressAllComments" value="true"/> </commentGenerator> <!--数据库链接URL,用户名、密码 --> <jdbcConnection driverClass="com.mysql.jdbc.Driver" connectionURL="jdbc:mysql://127.0.0.1/user" userId="root" password="root"> </jdbcConnection> <javaTypeResolver> <property name="forceBigDecimals" value="false"/> </javaTypeResolver> <!-- 生成模型的包名和位置--> <javaModelGenerator targetPackage="com.fantj.sbmybatis.model" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> <property name="trimStrings" value="true"/> </javaModelGenerator> <!-- 生成映射文件的包名和位置--> <sqlMapGenerator targetPackage="mapping" targetProject="src/main/resources"> <property name="enableSubPackages" value="true"/> </sqlMapGenerator> <!-- 生成DAO的包名和位置--> <javaClientGenerator type="XMLMAPPER" targetPackage="com.fantj.sbmybatis.mapper" targetProject="src/main/java"> <property name="enableSubPackages" value="true"/> </javaClientGenerator> <!-- 要生成的表 tableName是数据库中的表名或视图名 domainObjectName是实体类名--> <table tableName="user" domainObjectName="User" enableCountByExample="false" enableUpdateByExample="false" enableDeleteByExample="false" enableSelectByExample="false" selectByExampleQueryId="false"></table> </context></generatorConfiguration>
    
    • dao

    那就是线程池的面世的来头了,其为线程生命周期的开荒和财富缺乏难点提供了建设方案。通过对多少个职责重用线程,线程创造的开支被分派到了七个任务上。实际使用中,上文所述汤姆cat那样的Web服务器也是利用线程池机制来收取并管理多量产出的http恳求,能够透过其server.xml配置文件中的Connect节点的maxThreads/maxSpareThreads/minSpareThreads/acceptCount/maxIdleTime等参数举办线程池调优。

     Stream<String> streamEmpty = Stream.empty;
    
    int send_request() { size_t n = read_size(); vector<int> elements = vector<int>; if(read_elements(elements.size(), &elements[0]) < n) { return -1; } return 0;}
    
    3. 施用IDE创造逆向工程运营类

    图片 2

    线程池是一种八线程任务管理情势,管理进度团长职务增添到行列,然后在创制线程后活动运营这么些职责。这里援引wiki上边包车型大巴二个图如下:

    上述代码段成立的Empty Stream经常被用于制止null对象或零成分对象的streams(streams with no element)重临结果为null:

    不过在进一步目不暇接的例证中,特别是三三十二线程之间分享有些变量的景观下,析构器是比较矮效的。

    4. add一个Maven configuration

    图片 3图片 4

    public class UserDao { public User login(User user) { if ("aaa".equals(user.getUsername && "123".equals(user.getPsd { System.out.println; return user; } else { System.out.println; return null; } } public void register(User user) { System.out.println("注册成功!" + user.getUsername; }}
    

    图片 5

    public Stream<String> streamOf(List<String> list){ return lsit == null || list.isEmpty() ? Stream.empty() : list.streams();}
    

    最简易的污源回收情势是援引计数。对各种对象的话,都得以很清楚的通晓那个目的被引述了不怎么次,当指向这么些指标的引用为0时,该对象是足以被回收的。四个例子便是C++中的共享指针

    5. 本人的数据库和表结构

    图片 6

    • service

    单个职分管理时间相对短

    大家得以成立大肆Collection接口衍生类(Collection->List、Set、Queue)的Streams:

    int send_request() { size_t n = read_size(); auto elements = make_shared<vector<int>>(); // read elements store_in_cache; // process elements further return 0;}
    
    6. application配置文件
    server: port: 8080spring: datasource: name: test url: jdbc:mysql://127.0.0.1:3306/user username: root password: root # druid 连接池 type: com.alibaba.druid.pool.DruidDataSource driver-class-name: com.mysql.jdbc.Driver filters: stat maxActive: 20 initialSize: 1 maxWait: 60000 minIdle: 1 timeBetweenEvictionRunsMillis: 60000 minEvictableIdleTimeMillis: 300000 validationQuery: select 'x' testWhileIdle: true testOnBorrow: false testOnReturn: false poolPreparedStatements: true maxOpenPreparedStatements: 20mybatis: mapper-locations: classpath:mapping/*.xml type-aliases-package: com.fant.model#pagehelper分页插件pagehelper: helperDialect: mysql reasonable: true supportMethodsArguments: true params: count=countSql
    

    运作generator工程 自动生成代码

    亟待管理的义务数量比相当的大

    Collections<String> collection = Arrays.asList("a", "b", "c");Stream<Stirng> streamOfCollection = collection.stream();
    

    为了制止后一次调用该函数时还要读取成分,我们大概供给缓存它们。这种景色下,当vector对象超越效率域之后就清理它就不太合理了。因而,这里运用了shared_ptr。它保存了援用该指标的多少。这么些数字当该对象被引用时扩大,当引用的目的当先效用域时收缩。只要引用数量达到0,shared_ptr会自动删除底层的vector。

    User.java
    package com.fantj.model;import java.util.Date;public class User { private Integer id; private String username; private Date birthday; private String sex; private String address; public Integer getId() { return id; } public void setId(Integer id) { this.id = id; } public String getUsername() { return username; } public void setUsername(String username) { this.username = username == null ? null : username.trim(); } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex == null ? null : sex.trim(); } public String getAddress() { return address; } public void setAddress(String address) { this.address = address == null ? null : address.trim(); }}
    
    public class UserService { private UserDao userDao = new UserDao(); public User longin(User user) { return userDao.login; } public void register(User user) { userDao.register; }}
    

    降低能源消耗。通过重新使用已创制的线程裁减线程创立和销毁变成的开销。

    接下去的这段代码体现的是数组Stream:

    在上头的C++代码中,大家照例要求求理解的揭破我们曾几何时要拓宽内部存款和储蓄器管理。运维时遭逢会自动的寻找某些并非的内部存款和储蓄器并且释放它们。换句话说,它自动进行GC

    UserMapper .java
    package com.fantj.mapper;import com.fantj.model.User;import java.util.List;public interface UserMapper { int deleteByPrimaryKey(Integer id); int insert(User record); int insertSelective(User record); User selectByPrimaryKey(Integer id); int updateByPrimaryKeySelective(User record); int updateByPrimaryKey(User record); List<User> selectAll();}
    
    • loginServlet

    增加响应速度。当职务到达时,职分能够无需等到线程成立就能够登时施行。

    Stream<String> streamOfArray = Stream.of("a", "b", "c");
    

    引用计数

    UserMapper.xml
    <?xml version="1.0" encoding="UTF-8" ?><!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-mapper.dtd" ><mapper namespace="com.fantj.mapper.UserMapper" > <resultMap type="com.fantj.model.User" > <id column="id" property="id" jdbcType="INTEGER" /> <result column="username" property="username" jdbcType="VARCHAR" /> <result column="birthday" property="birthday" jdbcType="DATE" /> <result column="sex" property="sex" jdbcType="CHAR" /> <result column="address" property="address" jdbcType="VARCHAR" /> </resultMap> <sql > id, username, birthday, sex, address </sql> <select resultMap="BaseResultMap" > select <include ref /> from user </select> <select resultMap="BaseResultMap" parameterType="java.lang.Integer" > select <include ref /> from user where id = #{id,jdbcType=INTEGER} </select> <delete parameterType="java.lang.Integer" > delete from user where id = #{id,jdbcType=INTEGER} </delete> <insert parameterType="com.fantj.model.User" > insert into user (id, username, birthday, sex, address) values (#{id,jdbcType=INTEGER}, #{username,jdbcType=VARCHAR}, #{birthday,jdbcType=DATE}, #{sex,jdbcType=CHAR}, #{address,jdbcType=VARCHAR}) </insert> <insert parameterType="com.fantj.model.User" > insert into user <trim prefix="(" suffix=")" suffixOverrides="," > <if test="id != null" > id, </if> <if test="username != null" > username, </if> <if test="birthday != null" > birthday, </if> <if test="sex != null" > sex, </if> <if test="address != null" > address, </if> </trim> <trim prefix="values (" suffix=")" suffixOverrides="," > <if test="id != null" > #{id,jdbcType=INTEGER}, </if> <if test="username != null" > #{username,jdbcType=VARCHAR}, </if> <if test="birthday != null" > #{birthday,jdbcType=DATE}, </if> <if test="sex != null" > #{sex,jdbcType=CHAR}, </if> <if test="address != null" > #{address,jdbcType=VARCHAR}, </if> </trim> </insert> <update parameterType="com.fantj.model.User" > update user <set > <if test="username != null" > username = #{username,jdbcType=VARCHAR}, </if> <if test="birthday != null" > birthday = #{birthday,jdbcType=DATE}, </if> <if test="sex != null" > sex = #{sex,jdbcType=CHAR}, </if> <if test="address != null" > address = #{address,jdbcType=VARCHAR}, </if> </set> where id = #{id,jdbcType=INTEGER} </update> <update parameterType="com.fantj.model.User" > update user set username = #{username,jdbcType=VARCHAR}, birthday = #{birthday,jdbcType=DATE}, sex = #{sex,jdbcType=CHAR}, address = #{address,jdbcType=VARCHAR} where id = #{id,jdbcType=INTEGER} </update></mapper>
    

    压实线程的可处理性。线程是稀缺财富,假如无界定的创办,不仅仅会损耗系统能源,还会骤降系统的心旷神怡,使用线程池能够拓宽合併的分配,调优和监察。

    理所必然大家得以先创制熟谙的数组类型,再以它为源创立Stream,並且大家得以挑选Stream中隐含的要素数量:

    我们应用的C++中的援用指针可以利用于具备指标。如Perl、Python或许PHP等相当多言语都以利用这种措施。图片 7Java-GC-counting-references1.png

    修改运行类

    逆向生成代码后,大家还要求在开发银行类上增添一个@MapperScan("com.fantj.mapper")证明,告诉大家的Mapper需求扫描的包,那样就毫无每种Mapper上都助长@Mapper申明了。

    @SpringBootApplication@MapperScan("com.fantj.mapper")public class MybatisApplication { public static void main(String[] args) { SpringApplication.run(MybatisApplication.class, args); }}
    
    @javax.servlet.annotation.WebServlet(name = "LoginServlet",urlPatterns = "/LoginServlet")public class LoginServlet extends javax.servlet.http.HttpServlet { protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { //得到用户带过来的数据,封装到Bean对象中 String username = request.getParameter("username"); String psd = request.getParameter; User user = new User(); user.setPsd; user.setUsername; try { //调用Service方法 UserService userService = new UserService(); userService.longin; //登陆成功跳转到首页 request.getRequestDispatcher("/index.jsp").forward(request, response); } catch (Exception e) { e.printStackTrace(); //登陆失败,跳转到相关的提示页面 request.setAttribute("message","登陆失败了!!!"); request.getRequestDispatcher("/message.jsp").forward(request, response); } } protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { this.doPost(request, response); }}
    

    在JDK 1.5后引进的Executor线程池框架的最大亮点是把职责的交付和进行解耦。要进行义务的人只需把Task描述清楚,然后交给就能够。那么些Task职分是怎么被实践的,被哪个人推行的,哪一天实行的,提交的人就不用关怀了。在最上面包车型大巴Executor接口中定义了execute方法,该方法接收Runnable类型的职分指令,对顾客屏蔽底层线程的贯彻与调整细节,这是一种规范命令设计格局的采纳。如下为一段很简单的线程池代码例子:

    String[] arr = new String[]{"a", "b", "c"};Stream<String> streamOfArrayFull = Arrays.stream;Stream<String> streamOfArrayPart = Arrays.stream(arr, 1, 3);
    

    紫罗兰色的云彩指向的对象是如故被前后相继选取的目的。青蓝的云彩只怕意味着着正在实施的艺术中的变量只怕静态变量大概别的的事物,具体是何许还大概跟语言自己有关,大家这里先不爱护这么些。

    完善controller和service

    • registerServlet

    ExecutorService fixedThreadPool = Executors.newFixedThreadPool;

    当builder被用于钦定参数类型时,应被额外标记在评释左边,否则方法build()将成立三个Stream实例:

    蓝的圈子代表内部存储器中如故存活的指标,里边的数字代表它的引用计数。最终,米黄的圈子是不再被引述的对象。所以茶绿世界被以为是废物并且会被GC回收。

    UserController.java
    @RestController@RequestMappingpublic class UserController { @Autowired private UserService userService; @RequestMapping(method = RequestMethod.GET,value = "/delete/{id}") public void delete(@PathVariableint id){ userService.delete; } @RequestMapping(method = RequestMethod.POST,value = "/insert") public void insert(User user){ userService.insert; } @RequestMapping(method = RequestMethod.POST,value = "/update/{id}") public void update(@RequestParam User user){ userService.update; } @RequestMapping(method = RequestMethod.GET,value = "/{id}/select") public User select(@PathVariableint id){ return userService.selectById; } @RequestMapping(method = RequestMethod.GET,value = "/selectAll/{pageNum}/{pageSize}") public List<User> selectAll(@PathVariable("pageNum") int pageNum, @PathVariable("pageSize") int pageSize){ return userService.selectAll(pageNum,pageSize); }}
    

    fixedThreadPool.execute(newRunnable() {

    Stream<String> streamBuilder = Stream.<String>builder().add.add.add.build();
    

    援用计数看起来十一分好,可是总体艺术有叁个宏大的毛病,全体被循环引用涉及到的靶子的援引计数都不为0,所以这个目的永久不会被回收。如下图所示

    UserService.java
    package com.fantj.service;import com.fantj.model.User;import java.util.List;public interface UserService { /** 删除 */ public void delete; /** 增加*/ public void insert(User user); /** 更新*/ public int update(User user); /** 查询单个*/ public User selectById; /** 查询全部列表*/ public List<User> selectAll(int pageNum, int pageSize);}
    
    @javax.servlet.annotation.WebServlet(name = "RegisterServlet",urlPatterns = "/RegisterServlet")public class RegisterServlet extends javax.servlet.http.HttpServlet { protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { //得到用户带过来的数据,封装到Bean对象中 String username = request.getParameter("username"); String psd = request.getParameter; User user = new User(); user.setPsd; user.setUsername; try { //调用Service方法 UserService userService = new UserService(); userService.register; //注册成功跳转到登陆界面 request.getRequestDispatcher("/login.jsp").forward(request, response); //注册成功,我也可以跳转到首页 //request.getRequestDispatcher("/index.jsp").forward(request, response); } catch (Exception e) { e.printStackTrace(); //注册失败,跳转到相关的提示页面 request.setAttribute("message","注册失败了!!!"); request.getRequestDispatcher("/message.jsp").forward(request, response); } } protected void doGet(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { this.doPost(request, response); }}
    

    @Override

    方法generator()接受八个供应器Supplier<T>用于成分生成。由于生产流(resulting stream)被定义之后属于Infiniti流(即上前地穿梭生产),开拓者必得钦赐stream具备流的对象大小,不然方法generator()将不断生产直到jvm内部存款和储蓄器达到顶值(memory limit):

    图片 8Java-GC-cyclical-dependencies.png

    UserServiceImpl .java
    @Servicepublic class UserServiceImpl implements UserService { @Autowired private UserMapper userMapper; /** * 删除 * * @param id */ @Override public void delete { userMapper.deleteByPrimaryKey; } /** * 增加 * * @param user */ @Override public void insert(User user) { userMapper.insert; } /** * 更新 * * @param user */ @Override public int update(User user) { return userMapper.updateByPrimaryKey; } /** * 查询单个 * * @param id */ @Override public User selectById { return userMapper.selectByPrimaryKey; } /** * 查询全部列表,并做分页 * * @param pageNum 开始页数 * @param pageSize 每页显示的数据条数 */ @Override public List<User> selectAll(int pageNum, int pageSize) { //将参数传给这个方法就可以实现物理分页了,非常简单。 PageHelper.startPage(pageNum,pageSize); return userMapper.selectAll(); }}
    
    • login.jsp

    publicvoid run() {

    Stream<String> streamOfGenerated = Stream.generate -> "element").limit;
    

    标红的对象都并未被前后相继行使,也便是说这一个目的都是渣滓。可是因为援引计数的败笔,那个指标不会被回收并致使内部存款和储蓄器泄漏。

    浏览器访谈127.0.0.1/user/selectAll/0/1

    图片 9

    证实大家中标了。

    logger.info("thetask is running")

    上述代码将创制10个内容为“element”的生成流。

    有部分办法能够化解这一个难题,举个例子使用“弱援引”大概对循环援引的对象使用别的的征集算法。前述的Perl、Python等都施用了有些方法消除循环援用的难题。不过那么些主题材料超越了本篇小说的限制,我们不去钻探。相反的,大家将越加详实的介绍JVM接纳的GC方式

    一个小甜食

    有人问,get方法能够平素从浏览器地址中的url来测验,那post哀求怎么测量检验呢?个人提议用postman工具,也足以写测验类用代码来完毕测量试验。也能够采取idea的一个测量检验工具Test RESTful Web Service

    图片 10图片 11

    好了,配置格局大家介绍完了,作者在此间稍微聊一聊注脚开辟格局,个人提议一旦想用申明开垦,直接用jpa,能够更有利温馨的开荒。

    <%@ page contentType="text/html;charset=UTF-8" language="java" %><html> <head> <title>$Title$</title> </head> <body> <form action="${pageContext.request.contextPath}/LoginServlet" method="post"> 用户名:<input type="text " name="username"> 密码:<input type="password " name="psd"> <input type="submit" value="登陆"> </form> </body></html>
    

    }

    另一种成立Infiniti流的章程是由此调用方法iterate(),同样的它也急需选择方法limit()对指标流的因素大小举行限定:

    马克 and Sweep首先,JVM对于指标可达性的定义更切实,不相同于在此以前看来的海洋蓝云彩,JVM有一组非凡精通的目的,称为GC root:

    mybatis java api :
    • register.jsp

    });

    Stream<Integer> streamItreated = Stream.iterate(40, n -> n + 2).limit;
    
    • 本土变量 local variables
    • 活着的线程 active threads
    • 静态属性 static 田野s
    • JNI 援引 JNI referencesJVM用来追踪全体可达对象而且有限支撑不可达对象的内部存款和储蓄器能够利用的点子叫做标志清除算法,该算法由两局地组成
    • 标记等第从GC root开头遍历全数可达对象,而且在内部存款和储蓄器中保存路线
    • 清理阶段放活不可达对象的内部存款和储蓄器,並且保障在下三遍提请内部存款和储蓄器时能够选择
    UserMapper.java
    package com.fantj.mapper;import com.fantj.model.User;import org.apache.ibatis.annotations.*;import java.util.List;public interface UserMapper { /*int deleteByPrimaryKey(Integer id); int insert(User record); int insertSelective(User record); User selectByPrimaryKey(Integer id); int updateByPrimaryKeySelective(User record); int updateByPrimaryKey(User record); List<User> selectAll();*/ //如果实例对象中的属性名和数据表中字段名不一致,用@Result注解进行说明映射关系,我在这里只是告诉你怎么写 @Select("SELECT * FROM user") @Results({ @Result(property = "username", column = "username"), @Result(property = "sex", column = "sex"), @Result(property = "address",column = "address") }) List<User> selectAll(); @Select("SELECT * FROM user WHERE id = #{id}") @Results({ @Result(property = "sex", column = "sex"), @Result(property = "username", column = "username") }) User selectByPrimaryKey; @Insert({"INSERT INTO user(username,birthday,sex,address}) VALUES(#{userName}, #{birthday}, #{sex},#{address})"}) void insert(User user); @Update("UPDATE user SET userName=#{userName} WHERE id =#{id}") int updateByPrimaryKey(User user); @Delete("DELETE FROM user WHERE id =#{id}") int deleteByPrimaryKey;}
    

    在上头的例子中,生成线程池选取了工具类Executors的静态方法,设置了线程池中主题线程数和最大线程数均为5, 线程池中中国足球球组织一级联赛越基本线程数指标悠闲线程最大存活时间为0,同有的时候候采取LinkedBlockingQueue那样子的无界阻塞任务队列。除了newFixedThreadPool能够生成线程数固定大小的线程池,newCachedThreadPool能够生成二个可缓存且自动回收的线程池,newSingleThreadScheduledExecutor能够生成八个单个线程的线程池。newScheduledThreadPool还足以生成帮忙周期任务的线程池。

    迭代流即选择迭代的章程作为成分生产方式,类似于高级中学数学中的f),etc。上述例子中,生成流的首先个要素是迭代器iterate()中的第叁个要素40,从第2个成分开头的各样新因素都与上个成分有关,在此例中,生成流中的成分为:40、42、44、...78、80。

    JVM中不相同的GC算法,举个例子Parallel Scavenge,Parallel 马克+Copy 也许CMS对标志清理的兑现也许有略微差异。可是总体的定义上大概同样的。

    表明的一部分解释
    • @Select 是查询类的注释,全数的查询均选择那个
    • @Result 修饰再次来到的结果集,关联实体类属性和数据库字段一一对应,假使实体类* 属性和数据库属性名保持一致,就无需那些天性来修饰。
    • @Insert 插入数据库使用,直接传入实体类会自动剖判属性到相应的值
    • @Update 担任修改,也足以平素传入对象
    • @delete 负担删除
    <%@ page contentType="text/html;charset=UTF-8" language="java" %><html> <head> <title>$Title$</title> </head> <body> <form action="${pageContext.request.contextPath}/RegisterServlet" method="post"> 用户名:<input type="text " name="username"> 密码:<input type="password " name="psd"> <input type="submit" value="注册"> </form> </body></html>
    

    JDK中的Executor线程池框架是一个基于一组实施计谋调用、调节、奉行和调控线程的异步义务框架,其目标是提供一种将“职分交给”与“使时局营”分离开来的体制。作为Java线程池框架连接承Executor接口最为基本的类—ThreadPoolExecutor,有不能缺少对其源代码举办深入解析。由此,本节以ThreadPoolExecutor的源代码比方,先对以Executor接口为基本的类组织图进行二个相比较周详的显示,然后回归到源代码中,对线程池中任务怎么提交、如何试行任务等方面分别实行阐释。为了垄断篇幅,优异入眼逻辑,小说中引用的代码片段去掉了非器重部分。

    Java8提供了创建三大基础数据类型(int、long、double)stream的主意。由于Stream<T>是一个类接口,大家爱莫能助接纳泛型传参的章程宣示基础数据类型的stream,因而多个独特的接口就被成立出来了:IntStream、LongStream、DoubleStream。使用它们能够幸免不供给的电动装箱1以增加生产效能。

    这种艺术主要的某个正是不会导致内存泄漏。

    小心将application配置文件中的mybatis.mapper-locations:属性注视掉再开发银行项目。不然它会报错:Mapped Statements collection already contains value for com.fantj.mapper.UserMapper.insert 。意思是mapper中方法重新。

    地点的代码已经因而了测量试验,是能够跑起来的。

    图片 12

    IntStream intStream = IntStream.range;LongStream longStream = LongStream.rangeClosed;
    

    图片 13Java-GC-mark-and-sweep.png

    末尾多个甜食

    还大概有二个事物忘说了 -.-,正是用cmd来逆向生成代码。

    图片 14

    ①:跳转页面包车型地铁门径是写死的。小编在注册成功了现在,我可以跳转到首页上,也足以跳转到登入的分界面上。即使本身要选拔之中的叁个,就必须修改源代码...

    从上面包车型客车类协会图中得以看看,在JDK的J.U.C包上边首要包含了七个接口,分别是:

    方法range(int startInclusive, int endInclusive)创制了一个有序流(从startInclusive到endInclusive)。它使前面包车型地铁值每一种扩展1,但却不包蕴最终叁个参数,即此方法的结果是怀有上限的。方法rangeClosed(int startInclusive, int endInclusive)与range()大概一样,但它却包涵了最终七个值。那五个情势用于转移三大骨干数据类型的stream。

    不过缺点就是在GC的时候,应用线程或者需求暂停一段时间。因为只要目的的援引一直在不停地转换,那么将很难做出科学的总计。而应用程序暂停,JVM开端采撷垃圾的目前被叫作Stop-The Word 阶段

    宣称语句

    java -jar mybatis-generator-core-1.3.2.jar -configfile generator.xml -overwritesrc目录请忽略,那是变化的目录。好了 干货都享受了,多谢我们。0.0

    ②:二个作用对应一个Servlet,太费力了...写了LoginServlet,还要写RegisterServlet....

    Executor:叁个运营新职务的简易接口;

    除此以外,Java8之后,类Random也提供了进展方法用于转移基础数据类型的stream。举例,下述代码创设了三个包涵八个随机值的DoubleStream:

    小编们会发掘,不论怎么样Servlet上最终依旧跳转到相对应的JSP页面包车型地铁...也等于说,第一和第二步骤【封装数据、调用Service】我们得以包装起来...只要回去uri给Servlet跳转到JSP页面就好了

    ExecutorService:增添了Executor接口,扩展了某个用来管理线程池状态和天职生命周期的艺术以及协助Future再次来到值职责交给的不二秘籍;

    Random random = new Random();DoubleStream doubleStream = random.doubles;
    

    LoginAction

    归来的uri分二种情状:

    • 比方是转账,那么再次来到的是RequestDispatcher对象
    • 一经是重定向,那么重回的是字符串
    /** * Created by ozc on 2017/4/26. * <p> * 一个Action对应一个Servlet,Action负责处理具体的请求 */public class LoginAction { public Object login(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { Object uri ; //得到用户带过来的数据,封装到Bean对象中 String username = request.getParameter("username"); String psd = request.getParameter; User user = new User(); user.setPsd; user.setUsername; try { //调用Service方法 UserService userService = new UserService(); userService.longin; //登陆成功跳转到首页 request.getSession().setAttribute("user", user); //跳转到首页的时候需要重定向 //response.sendRedirect(request.getContextPath() + "/index.jsp"); //如果是重定向,那么返回的是字符串 uri = "/index.jsp"; return uri; } catch (Exception e) { e.printStackTrace(); //登陆失败,跳转到相关的提示页面 request.setAttribute("message","登陆失败了!!!"); //request.getRequestDispatcher("/message.jsp").forward(request, response); //如果是转发,那么返回的是RequestDispatcher对象 uri = request.getRequestDispatcher("/message.jsp"); return uri; } }}
    
    • LoginServlet就可以写成这么了:
     protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { //得到LoginAction对象 LoginAction loginAction = new LoginAction(); Object uri = loginAction.login(request, response); //是重定向 if (uri instanceof String) { response.sendRedirect(request.getContextPath; } else { //是转发,强转成是RequestDispatcher对象 ((RequestDispatcher) uri).forward(request, response); } }
    

    ScheduledExecutorService:增加了ExecutorService,增添了年限和推迟任务实行的法子;

    String类型也足以当做生成stream的源,那得益于方法chars()的赞助,别的由于JDK中尚无CharStream接口,IntStream也被用来表示字符流(stream of chars)

    RegisterAction

    • RegisterAction
    /** * Created by ozc on 2017/4/26. * * 一个Action对应一个Servlet,Action负责处理具体的请求 */public class RegisterAction { public Object register(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { Object uri ; //得到用户带过来的数据,封装到Bean对象中 String username = request.getParameter("username"); String psd = request.getParameter; User user = new User(); user.setPsd; user.setUsername; try { //调用Service方法 UserService userService = new UserService(); userService.register; //登陆成功跳转到登陆页面 uri = request.getRequestDispatcher("/login.jsp"); return uri; } catch (Exception e) { e.printStackTrace(); //注册失败,跳转到相关的提示页面 request.setAttribute("message","注册失败了!!!"); //request.getRequestDispatcher("/message.jsp").forward(request, response); uri = request.getRequestDispatcher("/message.jsp"); return uri; } }}
    
    • RegisterServlet
     protected void doPost(javax.servlet.http.HttpServletRequest request, javax.servlet.http.HttpServletResponse response) throws javax.servlet.ServletException, IOException { //得到RegisterAction RegisterAction registerAction = new RegisterAction(); Object uri = registerAction.register(request, response); //是重定向 if (uri instanceof String) { response.sendRedirect(request.getContextPath; } else { //是转发,强转成是RequestDispatcher对象 ((RequestDispatcher) uri).forward(request, response); } }
    

    那四个接口定义了JDK中Executor线程池框架的标准作为,那四个接口的现实性代码能够参照JDK的代码。限于篇幅,这里就不对一一艺术举行依次详细描述了。类图中AbstractExecutorService类是贰个抽象类,提供了线程池框架的一对模板方法,具体贯彻由其子类,ThreadPoolExecutor和ScheduledThreadPoolExecutor分别完结。Executors是个工具类,里面提供了大多静态方法,根据顾客的须要选取回到区别的线程池实例。

    IntStream streamOfChars = "abc".chars();
    

    思考

    到近年来截至,大家搞了多少个Action类来封装Servlet的逻辑代码,大家再一次看回Servlet的代码。

    图片 15那边写图片描述图片 16此间写图片描述

    能够很精通地窥见:多个落到实处分化效用的Servlet仅仅是调用的Action差异....假诺是唯有调用的Action差异【通过反射来调用差异的Action】,那么我们应有想开利用二个Servlet来保管整个项目,也正是说:整个web项目独有多当中坚的调控器

    问题:

    ①:我们在以前是一直指明Servlet的投射路线了,今后要ActionServlet管理全部的央求,大家就算定八个准绳:举个例子后缀为.action的,那么都交由基本调控器ActionServlet来支配....

    ②:未来整整的要求已经交由ActionServlet控制,那怎么了解调用的是哪些Action???大家得以经过伏乞的uri,举个例子:http://localhost:8080/login.action,在那之中login就象征的是调用LoginAction..也正是说login=LoginAction,大家能够透过properties文件来配置..

    ③:现在我们曾经通晓了调用的是哪个Action了,但是Action可能不仅独有二个办法,大家还要在调用的时候,钦赐的办法名是什么样.那很简短,平日大家都以义务分工明显的,method=login....何况,调用的Action和现实性的情势也有涉嫌的,不容许是孤立存在的。因此,我们的配置文件是无法接纳properties的,必要动用XML

    ④:在调用方法的时候,是回去一个Object的uri的,uri的品种只怕是String、也得以能是RequestDispatcher、而且重返的结果也许有二种情景的【恐怕跳转到首页,也说不定跳转到登入分界面】

    ⑤:Action调用的点子和重返的uri也是是有提到的!.....差异的Action调用分裂的措施,再次来到的uri也是见仁见智的....

    ⑥:要跳转到哪个页面上,能够透过标志量来识别....比方:success表示成功施行,即使要重定向那么多加个type类型,假若不重定向就从未有过type类型..路线使用path来表示..由此,在实际的Action中,就无需再次来到具体的uri,只要回到二个标记量就能够

    画一张图来梳理一下思路:

    图片 17那边写图片描述

    对于类组织图中左侧半有个别概念了ThreadPoolExecutor大旨类的分子变量,满含创建线程的类工厂—ThreadFactory/DefaultThreadFactory,用以描述具体义务实施线程的里边类—Worker(其承袭AQS框架和Runnable接口)和提供线程池工作饱和计策的—RejectedExecutionHandler。

    下例中经过特征的正则表明式将一个字符串割裂成(break into)其子串。

    XML配置

    咱俩得以写出那般的XML配置,当ActionServlet开头化的时候,读取XML配置文件,就知道调用的是怎么Action,Action中的什么形式,以及跳转到哪个页面上了

    <?xml version="1.0" encoding="UTF-8" ?><mystruts> <package> <action name="login" className="zhongfucheng.servlet.LoginServlet" method="login"> <!--是否存在type属性,存在则是重定向,不存在则是转发--> <!--result的值表示的就是跳转的路径--> <result name="success" type="redirect">/index.jsp</result> <result name="fail">/message.jsp</result> </action> <action name="register" className="zhongfucheng.servlet.RegisterServlet" method="register"> <!--是否存在type属性,存在则是重定向,不存在则是转发--> <!--result的值表示的就是跳转的路径--> <result name="success">/message.jsp</result> <result name="fail">/message.jsp</result> </action> </package></mystruts>
    

    为了更加好地保管那一个新闻,大家应当利用JavaBean来对它们封装

    • ActionMappingManager-------管理整个的Action
    /** * Created by ozc on 2017/4/26. * * 该类管理着全部的Action * * 要管理全部的Action,就需要用一个容器来装载这些Action * * 选择Map集合是最合适的,可以通过key来得到Action,key就是<action name=><action/>中的name属性 * */public class ActionMappingManager { private Map<String, ActionMapping> map = new HashMap<>(); //注意:外界都是通过name来得到对应的Action的,并不会获取得到整个Manager public ActionMapping getActionMapping(String name) { return map.get; }}
    
    • ActionMapping----表示单个的Action
    public class ActionMapping { //所有的results private Map<String, Results> results; //关键字name private String name; //要调用的Action路径 private String className; //Action中的方法 private String method; public Map<String, Results> getResults() { return results; } public void setResults(Map<String, Results> results) { this.results = results; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String getClassName() { return className; } public void setClassName(String className) { this.className = className; } public String getMethod() { return method; } public void setMethod(String method) { this.method = method; }}
    
    • Results---表示的是结果视图
    /** * Created by ozc on 2017/4/26. * * 该类表示的是结果视图 * * * */public class Results { //方法返回的标识 private String name; //要跳转的方式 private String type; //要跳转的页面 private String page; public String getName() { return name; } public void setName(String name) { this.name = name; } public String getType() { return type; } public void setType(String type) { this.type = type; } public String getPage() { return page; } public void setPage(String page) { this.page = page; }}
    

    线程有多样情状:新建、就绪、运行、阻塞、过逝。对于线程池来说,同样也持有各类景况:RUNNING, SHUTDOWN, STOP, TIDYING, TERMINATED。线程池状态转变图如下:

    Stream<String> streamOfString = Pattern.compile.spitAsStream("a", "b", "c");
    

    ActionMappingManager读取配置文件

    在ActionMappingManager中,应该读取配置文件,然后把音信全体打包到里面去...

    /** * Created by ozc on 2017/4/26. * * 该类管理着全部的Action * * 要管理全部的Action,就需要用一个容器来装载这些Action * * 选择Map集合是最合适的,可以通过key来得到Action,key就是<action name=><action/>中的name属性 * */public class ActionMappingManager { private Map<String, ActionMapping> allAction ; public ActionMappingManager() { this.allAction = new HashMap<>(); //读取配置文件信息 init(); } public void init() { /********通过DOM4J读取配置文件信息*********/ try { //得到解析器 SAXReader saxReader = new SAXReader(); //读取在类目录下的mystruts.xml文件 InputStream stream = ActionMappingManager.class.getClassLoader().getResourceAsStream("mystruts.xml"); //得到代表XML文件的Document对象 Document document = saxReader.read; //通过XPATH直接得到所有的Action节点 List list = document.selectNodes("//action"); //得到每个Action节点 for (int i = 0; i < list.size { Element action =  list.get; //把得到每个Action的节点信息封装到ActionMapping中 ActionMapping actionMapping = new ActionMapping(); String name = action.attributeValue; String method = action.attributeValue; String className = action.attributeValue("className"); actionMapping.setName; actionMapping.setMethod; actionMapping.setClassName(className); //得到action节点下的所有result节点 List results = action.elements; //得到每一个result节点 for (int j = 0; j < results.size { Element result =  results.get; //把得到每个result节点的信息封装到Results中 Results results1 = new Results(); //得到节点的信息 String name1 = result.attributeValue; String type = result.attributeValue; String page = result.getText(); results1.setName; results1.setType; results1.setPage; //把result节点添加到ActionMapping的集合中 actionMapping.getResults().put(name1, results1); } //最后把得到每个ActionMapping的信息添加到ActionMappingManager中 allAction.put(name, actionMapping); } } catch (DocumentException e) { new RuntimeException("初始化的时候出错了!“" + e); } } //注意:外界都是通过name来得到对应的Action的,并不会获取得到整个Manager public ActionMapping getActionMapping(String name) { return allAction.get; }}
    

    图片 18

    Java NIO2类文件允许通过艺术lines()生成文书文件的Stream<String>。文本的每一行都会化为stream的七个因素:

    ActionServlet

    运用init()方法只加载成立一个ActionManagerMapping对象,并安装在Web容器运维了该Servlet就运营

    /** * Created by ozc on 2017/4/26. * * * Web容器一启动的时候,该类就应该加载了,在web.xml文件中配置onloadStart */public class ActionServlet extends HttpServlet { //该对象封装了所有的XML信息 ActionMappingManager actionMappingManager ; @Override public void init() throws ServletException { //让ActionMappingManager对象只有一个! actionMappingManager = new ActionMappingManager(); } protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { try { //得到用户的uri String uri = request.getRequestURI(); //截取uri的关键部分-----截完应该是login uri = uri.substring(uri.lastIndexOf + 1, uri.lastIndexOf; //通过uri得到配置文件中的action信息 ActionMapping actionMapping = actionMappingManager.getActionMapping; //得到action的类名,方法名 String className = actionMapping.getClassName(); String method = actionMapping.getMethod(); //通过反射创建出Action的对象,调用对应的方法 Class t = Class.forName(className); Object o = t.newInstance(); //注意:这里的参数是接口的class,不是单纯的request的class,单纯的class是实现类 Method m = t.getMethod(method, HttpServletRequest.class, HttpServletResponse.class); //调用方法,得到标记 String returnFlag =  m.invoke(o, request, response); //通过标记得到result的具体信息 Results result = actionMapping.getResults().get(returnFlag); String type = result.getType(); String page = result.getPage(); //判断是重定向还是转发,为空就是转发,反则是重定向 if (type == null) { response.sendRedirect; } else { request.getRequestDispatcher(request.getContextPath.forward(request, response); } } catch (Exception e) { e.printStackTrace(); } } protected void doGet(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { this.doPost(request, response); }}
    

    切实的Action的主意只要回到贰个标记量就能够,大家由此标志量来获得实际的跳转页面url和跳转的章程的。。。

    图片 19这边写图片描述

    由于观念web的Controller模块存在破绽:

    • 某些职能重复使用,代码过于重复了。
    • 跳转的页面写死了。退换供给的时候供给改造源代码

    本博文重要模仿Struts的花费流程

    • 使用一个ActionServlet核心调节器来治本整个的Web央浼,写XML配置文件,读取配置文件。
    • ActionMapping封装了Action的为主新闻,在XML配置文件中就是读取Action的大旨音讯,封装到JavaBean上,最终动用ActionMapping类的成团统一管理起来。
    • 当顾客访谈的时候,我们依据url约等于Action的称呼反射出相应的类,来对其实行操作
    • 基于XML文件的配置消息来鲜明跳转方法、跳转的url

    笔者们未来上学的是Struts2,其实Struts1和Struts2在才能上是向来不十分大的关系的。 Struts2实在基于Web Work框架的,只但是它的放大未有Struts1好,因此就拿着Struts这厮气推出了Struts2框架。

    因此,学习Struts2的时候,不驾驭Struts1是绝非别的关系的。

    在前面,已经认证了怎么要引进Struts框架,其实正是为着巩固支付成效...

    Struts2框架预先达成了一部分意义:

    • 恳请数据自动封装
    • 文本上传的效应
    • 对国际化成效的简化
    • 数据效验功用.......等等

    作者们就一平昔讲学Struts2的开荒步骤是何等吧....在理解它的细节此前,先要把布置蒙受搭好!

    一体化的struts中的jar包有80多个,我们普通支付是不须求那么七个的。诚如大家导入的jar包有8个:

    • commons-fileupload-1.2.2.jar
    • commons-io-2.0.1.jar
    • struts2-core-2.3.4.1.jar 【struts2骨干职能包】
    • xwork-core-2.3.4.1.jar
    • ognl-3.0.5.jar 【Ognl表明式作用支撑表】
    • commons-lang3-3.1.jar 【struts对java.lang包的扩大】
    • freemarker-2.3.19.jar 【struts的价签模板库jar文件】
    • javassist-3.11.0.GA.jar 【struts对字节码的拍卖有关jar】

    图片 20此间写图片描述

    在web.xml中布署的过滤器,其实正是在为struts举办开头化专门的职业

    值得注意的是:借使该web.xml配置了四个fileter,那么struts的filter需求在结尾面!

    <!-- 引入struts核心过滤器 --> <filter> <filter-name>struts2</filter-name> <filter-class>org.apache.struts2.dispatcher.ng.filter.StrutsPrepareAndExecuteFilter</filter-class> </filter> <filter-mapping> <filter-name>struts2</filter-name> <url-pattern>/*</url-pattern> </filter-mapping>
    

    开山篇大家早已说了,Servlet的事情代码,大家都施用Action来替代...Action类日常持续着ActionSupport

    Action类也叫动作类,拍卖诉求的类。

    public class HelloAction extends ActionSupport { @Override public String execute() throws Exception { System.out.println("helloworld"); return "success"; }}
    

    至于execute()方法是何许,大家先不要去管它,为何要回去三个String,大家也绝不去管它....假使记住开荒步骤,并且,我们的Action类是要承袭ActionSupport类的

    有关配置struts.xml,大家得以在文书中找到绝对应的模版代码的...最终修改成上面那些样子就行了:

    <?xml version="1.0" encoding="UTF-8" ?> <!DOCTYPE struts PUBLIC "-//Apache Software Foundation//DTD Struts Configuration 2.0//EN" "http://struts.apache.org/dtds/struts-2.0.dtd"><struts><package name="hello" extends="struts-default"> <action name="hello" method="execute"> <result name="success">/index.jsp</result> </action></package></struts>
    

    看完上边的配备文件,是老大像大家开山篇写的struts框架的布署文件的....

    在地方栏中一贯输入hello,就跳转到index.jsp页面了。何况,execute()中的语句被施行了...

    图片 21此处写图片描述

    咱俩来轻易地问询一下Struts的实践流程,然后再逐级对地点的费用步骤的一部分开展讲授....

    上面小编说的都以struts流程的首要:

    • 加载web.xml文件
    • 找到大家安插的filter中的StrutsPrepareAndExecuteFilter
    • StrutsPrepareAndExecuteFilter在在这之中实践init()方法
    • 一直到Dispatcher dispatcher = init.initDispatcher;,初始化dispatcher
    • 聊聊Java进级之并发基础技术,非常完整。在初步化dispatcher的时候加载struts-default.xml和大家配备的struts.xml

    下边用GIF图来看看它的进行进度:

    图片 22那边写图片描述

    有心人的情侣可能会发觉,大家在struts.xml的package节点下,extends了struts-default....那struts-default毕竟是怎么着东西啊?

    大家找到它的源码:

    图片 23这里写图片描述

    小编们开掘了一大堆的Bean,interceptor,result-type,interceptor-stack...下面小编来上课一下它们是干嘛用的...

    • bean内定了struts在运作的时候供给创制的对象类型
      • 在运转struts的时候,恐怕须求成立一些指标,那么就由此Bean来内定
    • interceptor是struts定义的拦截器,一共有三拾二个
      • 前方已经说了,Struts为大家兑现了一些效果与利益,正是通过拦截器来兑现的
    • result-type是跳转结果的连串
      • Action业务方法中的再次回到值,大家发掘多少个实用的:redirect、dispatcher、redirectAction【重定向到Action财富】、stream...跳转结果的品种也在这里定义了
    • interceptor-stack是拦截器的栈
      • 拦截器有叁17个,我们兴许会使用过多的拦截器,不容许二个三个来调用,于是提供了阻止器栈...其实能够轻易看成文本夹和文书之间的关联
    • default-interceptor-ref是暗许实施的遏止器栈
    • default-class-ref class是私下认可的奉行Action类

    还要补充的就是:暗中认可的拦截器栈有十八个拦截器....

    在具体说说线程池的各类情景在此以前有必不可缺整合ThreadPoolExecutor宗旨类的代码实行一些解析,在此类的代码中对此线程池的三种情况定义如下:

    Path path = Paths.get("C:\file.txt");Stream<String> streamOfString = Files.lines;Stream<String> streamWithCharset = Files.lines(path, Charset.forName;
    

    拦截器和过滤器

    拦截器和过滤器都以阻止财富的

    拦截器只拦截Action须要,是struts的概念...

    过滤器拦截web的具备能源,是Servlet的概念...

    private final AtomicInteger ctl = newAtomicInteger(ctlOf(RUNNING, 0));

    ps:在艺术lines()中也可以因而Charset设置文件编码。

    小总结

    服务器运行的时候,其实正是加载了web.xml文件,然后调用init()方法去加载struts.xml和struts-default.xml之类的文书.....

    注意:那会儿的拦截器是还从未被调用的

    服务器运营的阶段,仅仅是加载了各样的xml文件...那么当大家拜候Action的时候,它的实施流程是怎么的吧?

    • 首先,它会成立大家在struts.xml中布署的Action对象
    • 接着,它会遵从私下认可的依次实施十多少个拦截器【也便是调用默许拦截器栈】
    • 最后,它会推行Action的事情方法【也正是execute(),我们在struts.xml文件中布局了怎么,就施行如何业务方法】

    值得注意的是:每访谈Action叁回,它就能创制八个目标...它并不是和Servlet一样独有叁个对象...于是它是线程安全的.

    那是大家的struts.xml的剧情,相信将来对它也不会太不熟悉了...

    <struts><package name="hello" extends="struts-default"> <action name="hello" method="execute"> <result name="success">/index.jsp</result> </action></package></struts>
    

    package其实正是包,那包用来干什么?包就是用来管理Action

    日常来讲,大家都以三个政工模版对应四个package

    private static final int COUNT_BITS =Integer.SIZE - 3;

    万一调用生成操作就能实例化一个stream并生成三个可获取的援用,但施行终端操作会使得stream不恐怕访问。为了求证这点,我们无妨先忘记它,究竟实践是核准真理的独一规范。以下代码若是不挂念冗长的话将是卓有效能的:

    name

    name是包的名字,值得注意的是,包的名目是无法重新的。

    private static final int CAPACITY = (1 << COUNT_BITS) - 1;

    Stream<String> stream = Stream.of("a", "b", "c").filter(element -> element.contains;Optional<String> anyElement = stream.findAny();
    

    extends

    extends代表的是现阶段包承继着哪些包。在struts中,包必须求承接着struts-default

    // runState is stored in the high-order bits

    不过如果大家在实践终端操作后再一次使用同一的引用,则会不可幸免的触发IllegalStateException。

    abstract

    在package中还应该有abstract这一个特性,使用该属性时:评释当前包被其余的包承接...并且,在package下无法有action,不然会出错!

    private static final int RUNNING = -1 << COUNT_BITS;

    Optional<String> firstElement = stream.findFirst();
    

    namespace

    在package中还会有namespace那个性情---名称空间....它是作为路线的一有的的,暗许是"/"

    action:配备央浼路线与Action类的炫人眼目关系

    private static final int SHUTDOWN = 0<< COUNT_BITS;

    IllegalStateException是一个运作时特别(RuntimeException),即编写翻译器将不会提醒此错误。因而必需记得,JAVA8 不允许重复使用stream这一规划是合乎逻辑的,因为stream从规划上目的在于提供叁个将轻巧操作(指函数体兰秋素的有关操作)的行列,并不是积攒元素。由此想让原先的代码不荒谬办事我们得先改一改:

    name

    name是呼吁路线的名字

    private static final int STOP = 1 << COUNT_BITS;

    List<String> elements = Stream.of("a", "b", "c").filter(element -> element.contains .collect(Collectors.toList;Optional<String> anyElement = elements.stream().findAny();Optional<String> firstElement = elements.stream().findFirst();
    

    class

    class是管理action类的人名

    private static final int TIDYING = 2<< COUNT_BITS;

    想要实行源数据集的操作集并集聚它们,你必要以下七个部分——源、中间操作(Intermediate operations)和终止操作(terminal operation)。中间操作再次来到的是四个新的可操作stream。譬如,为了在一个蕴涵少些因素Stream的底子之上新建Stream,大家能够调用方法skip():

    method

    method是调用的措施名称

    result代表的是Action中职业方法重返的值

    private static final int TERMINATED = 3 << COUNT_BITS;

    Stream<String> oneModifiedStream = Stream.of("abcd", "bbcd", "cbcd").skip;
    

    name

    name是action管理回来的值

    // Packing and unpacking ctl

    假如急需每每改动,则足以应用数14回中等操作。假诺我们还要求将Stream<String>中各样字符串替换为其子串subString,则能够运用skip相连的艺术实现:

    type

    type是跳转的项目

    private static int runStateOf { return c & ~CAPACITY; }

    Stream<String> twiceModifiedStream = stream.skip.map(element -> element.subString;
    

    文本值

    文本值是跳转的路线

    跟前已经说了,一个package应该相应多少个事情模块..目标即是把效果分开出来...

    struts为了让大家更加好地管理xml文件,它仍是能够这么做:在差异的模块中用分歧的xml文件举办描述...

    图片 24此处写图片描述

    末段在struts.xml文件大校其引进就能够..

    <!--struts在运行的时候总会加载这个文件--><!--总配置文件总引入其他的文件--><struts> <include file="privilegeaction/privilege.xml"/> <include file="useraction/hello.xml"/></struts>
    

    就算作品有错的地方应接指正,大家互相沟通。习贯在微信看技术小说,想要获取越来越多的Java能源的同学,能够关怀微教徒人号:Java3y

    private static int workerCountOf { return c & CAPACITY; }

    正如您所见,上例中map()使用Lambda表明式作为其参数对stream中的各因素进行拍卖。stream本身是毫无价值的,编制程序职员最感兴趣的莫过于是结束操作(terminal operation),它能够是一个因素也得以是贰个作为。独有在截至操作里本领对各类stream实行应用。正确的且最有利的stream操作方法正是Stream Pipeline,即stream源->中间操作->终结操作。如例:

    private static int ctlOf(int rs, int wc) {return rs | wc; }

    List<String> list = Arrays.asList("abc1", "abc2", "abc3");long size = list.stream .map(element -> element.substring.sorted;
    

    对此地点代码中定义的常量ctl是对线程池的运维情形和线程池中有效线程的数码举行调控的多少个叁11位字段,它包括两片段的音信:当中高二人表示线程池的周转境况,低二十七位代表线程池内有效线程的数据 (workerCount)。COUNT_BITS 正是29,CAPACITY正是1左移贰15位减1,这一个常量表示workerCount的上限值,差不离是5亿。其余这里还定义了八个静态方法分别为,runStateOf—获取运转境况;workerCountOf—获取活动线程数;ctlOf—获取运营状态和活动线程数的值。

    中等操作是懒式调用的,那象征唯有在终止操作须求它们的时候中间操作才会被晋升。为了印证这一个真相,假象我们有个主意wasCalled(),每当它被唤醒时使内部变量counter自增。

    RUNNING:处于RUNNING状态的线程池还不错新任务,以及对新扩展长的天职进行拍卖。

    private long counter;private void wasCalled() { counter++;}
    

    SHUTDOWN:处于SHUTDOWN状态的线程池不还不错新职分,不过足以对已增多的任务进展管理。

    接下去让大家在filter()操作中唤起wasCalled():

    STOP:处于STOP状态的线程池不收受新职分,不管理已加多的任务,而且会暂停正在管理的职务。

    List<String> list = Arrays.asList(“abc1”, “abc2”, “abc3”);counter = 0;Stream<String> stream = list.stream().filter(element -> { wasCalled(); return element.contains;
    

    TIDYING:当有着的职务已甘休,ctl记录的"职务数量"为0,线程池会变为TIDYING状态。当线程池变为TIDYING状态时,会试行钩子函数terminated()。terminated()在ThreadPoolExecutor类中是空的,若客商想在线程池变为TIDYING时,实行对应的拍卖;能够通过重载terminated()函数来完成。

    由于有多少个变量,想象中filter()中的代码块将被实践叁回,wasCalled()实行三次以往counter的值应该为3,然而进行之后counter并未爆发转移,还是为0,也正是说filter()一次也未曾被唤起,那几个缘故就算贫乏了收尾操作(terminal operation)。那接下去我们不要紧再上述代码的底蕴之上增多贰遍map()操作和八个停止操作——findFirst(),并运用打日志的艺术扶持我们掌握方法调用机遇及顺序。

    TERMINATED:线程池透顶停止的状态。

    Optional<String> stream = list.stream().filter( element -> { log.info was called!"); return element.contains.map(element -> { log.info was called!"); return element.toUpperCase.findFirst();
    

    在上文第三节内容中,已经交付了贰个创办轻易线程池的例证,在那之中调用了JDK的ThreadPoolExecutor大旨类的构造函数来创设的线程池实例。在这一节内容中,通过解析ThreadPoolExecutor主题类的构造函数以及参数来看下如何创制三个Executor线程池以及在开创时候需求关切如何要素?

    日记结果展现filter()被唤起了五遍,而map()仅仅被调用二次,这是出于管道流是垂直实施的。在此例中首先个因素不知足filter()的渴求,因而filter()被调用第二遍以寻觅合适的结果,通过之后即开展map()操作,此时就从未第贰遍机缘实施filter()操作了。findFirst()就能够找寻源数据汇总第多少个富含“2”的字符串的全大写字符串了。由此,懒调用使得不必相继调用两个中等操作和map技术到位职分了。

    public ThreadPoolExecutor(intcorePoolSize,

    从质量的角度考虑,正确的实施顺序是使用上文提到的流式管道(Stream Pipeline):

    intmaximumPoolSize,

    long size = list.stream().map(element -> { wasCalled(); return element.substring.skip.count();
    

    longkeepAliveTime,

    施行这段代码将使counter自拉长3次,那意味着stream的办法map()将被调用3次,但说起底size的值为1。那表示结果流(resulting stream)中单独唯有叁个因素,无庸置疑在贰次新闻管理中前后相继跳过了一遍拍卖。即使大家改动skip的实行顺序,counter将只自增加一次。也便是map()只被调用一回:

    TimeUnit unit,

    long size = list.stream.map(element -> { wasCalled(); return element.substring.count();
    

    BlockingQueue workQueue,

    以上示例告诉大家三个法则:用于减少流桐月素数量的中间操作,应当放置在管理操作从前。因而,保障在您的Stream Pipeline法规中依照那样的逐个编码:skip() --> filter() --> distinct()

    ThreadFactorythreadFactory,

    API提供了多量的极限操成效以聚焦三个stream为一种数据类型或变量。举例:count、min,可是那一个点子都以预约义的。但若是客户必要自定义三个stream的集聚操作呢?官方提供了三个艺术用以完毕此类供给:reduce() 和 collect()。

    RejectedExecutionHandler handler) {

    此措施提供了二种变种,不一样之处是它们的签订协议以及重临类型。reduce()方法具备下列参数:identify

    if (corePoolSize < 0 ||

    • 储存器的初叶值或当stream为空时的私下认可值。accumulator -

      提供设定聚合成分之逻辑的成效,每一回规约储存器都会创立三个新的值,新值的高低相等stream的大小,何况独有上三个值是可用的。那可怜有利于进步品质。combiner

      提供聚合accumulator桐月素的效用,combiner是不二法门二个能从分歧线程以相互情势聚合积存器中结果的主意。好,让大家来实战一下呢:

      OptionalInt reduced = IntStream.range.reduce -> a + b);

    maximumPoolSize <= 0 ||

    reduced = 6 = 1 + 2 + 3。

    maximumPoolSize < corePoolSize||

    int reducedTwoParams = IntStream.range.reduce(10,  -> a + b);
    

    keepAliveTime < 0)

    reducedTwoParams = 16 = 10 + 1 + 2 + 3。

    throw newIllegalArgumentException();

    int reducedParams = Stream.of .reduce(10,  -> a + b,  -> { log.info("combiner was called"); return a + b; });
    

    if (workQueue == null || threadFactory== null || handler == null)

    这一结果与上文中的16同一,并且不会打出日记,因为combiner没有被唤起。为了唤起combiner,stream应当是互为的:

    throw new NullPointerException();

    int reducedParallel = Arrays.asList.parallelStream() .reduce(10,  -> a + b,  -> { log.info("combiner was called"); return a + b; });
    

    this.corePoolSize = corePoolSize;

    此刻,结果形成36,并且combiner被唤起了四遍。规约运行的算法为:每当stream中的成分通过identify时accumulator均被调用,最后积攒器调用了3次。上述行为是相互完结的,因而产生了(10+1=11; 10+2=12; 10+3=13;)。最后combiner混合了一遍的结果,通过一回迭代完毕运算(12+13=25; 25+11=36;)。

    this.maximumPoolSize = maximumPoolSize;

    stream的法规也得以被其余的实现方法施行——collect()。它接受了一个名称叫collector的参数,此参数注脚规约的流水线。官方已经成立了预约义的搜聚器,我们得以在这几个搜聚器的拉拉扯扯下访问它们。下边我们将见到选取List作为持有stream的来源:

    this.workQueue = workQueue;

    List<Product> productList = Arrays.asList(new Product(23, "potatoes"), new Product(14, "orange"), new Product(13, "lemon"), new Product(23, "bread"), new Product(13, "sugar"));
    

    本文由澳门皇家赌场真人在线发布于皇家赌场游戏,转载请注明出处:聊聊Java进级之并发基础技术,非常完整

    关键词: