0%

前言

自学这件事,要坚持下来真的挺耗费精神力的。本来打算把博客系统敲完,遇到面试,要准备,参加面试几轮几轮的面,准备入职的事,又有新面试等等,对入职公司的技术栈的研究涉及go,又大概看了go。测试学院开学,当了助教,也需要上课,答疑解惑。精神分散,还要做家务煮饭什么的,还是比较难办。差点把这个博客计划半途而废了。然后想起来还有件事没有利索,回头继续前进,一定完成!做一件成一件!

2020年6月入职现在的公司开启上班模式后这件事又耽搁了几个月,期间根据公司实际,研习了很多客户端的技术,博客代码的事有中断,后继续,目前是2021年6月7日,实际前前后后已经完成一个多月,打算对第一阶段的博客代码和套路做个总结。下一个阶段的总结应该是要前后端分离,并带上VUE相关内容的。

本文不适合跟操作,仅适合查看涉及的知识点,或扩充一二。

我的项目地址:https://gitee.com/windanchaos/my-blog-v2

师出同门的博客地址(可以大致跟敲):https://onestar.newstar.net.cn/types/33

李仁密教课的地址(我很多地方没跟,比如持久框架和很多细节):https://www.bilibili.com/video/BV13t411T72J

前置动作

  • jQuery速度学习一下,以便在操控界面元素上能有思路
  • mybatis速度学习一下,以便脱离视频教程的持久化方法

用户故事

三个关键点角色、功能、商业价值。

模板:作为一个(角色),我可以做什么,从而达到什么目的。

个人博客系统的用户故事

角色:普通访客、管理员(我)

这里的概念是头一次听到和见到,类似一个产品经理的视角看待问题。

访客的用户故事

  • 可以分页查看所有博客
  • 快速查看博客数最多的6个分类
  • 可以查看所有的分类
  • 可以查看某个分类下的博客列表
  • 查看标记博客最多的10个标签
  • 查看所有标签
  • 查看标签下的博客列表
  • 可以根据年度时间线查看博客列表
    阅读全文 »

一点总结

由于自己本身就对shell中常用的命令有所了解,所以基础的就不啰嗦了。在我之前的博客中已经有不少内容

就写过的很多shell脚本经验看,最近作为助教又在跟着霍格沃兹第三期,又有了新感受。结合以前的经验,做个简单的总结。

  • 代码要规范
  • 虽然是shell,代码在逻辑上也要缜密

Linux文本三剑客

awk

最基本的作用,按规则输出列。

前置学习printf 或print。

printf

命令格式:

printf ‘匹配式’ 输入内容

它的输出全部当成字符串。所以需要自己来设置换行或空格。

%ns

输出字符串。n是数字指代输出几个字符

%ni

输出整数。n是数字自带输出几个数字。

%m.nf

输出浮点数。m是总的位数,n是小数位数

下面是例子,文本demo.txt

ID Name Linux PHP MySQL Java
1 Liming 82 55 58 87

阅读全文 »

MyBatis

ORMapping: Object Relationship Mapping 对象关系映射的一种流行框架。相同技术还有Hibernate。两者对比,可参考:https://www.cnblogs.com/javacatalina/p/6590321.html

ORMapping是Java 到 MySQL 的映射,开发者可以以面面向对象的思想来管理理数据库。

使用套路

两种使用方式

  • mybatis原生方式
  • mybatis动态代理

两者的区别是在获取到sqlsession链接后,操作对象的动作差异。下面举例原生的方式。之后默认用的动态代理。

1
2
3
4
// statement是mapper中的‘namespace.方法’
String statement = "com.chaosbom.mapper.AccoutMapper.save";
Account account = new Account(1L,"张三","123123",22);
sqlSession.insert(statement,account);

mapper.xml

1
2
3
4
5
6
7
8
9
<?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.chaosbom.mapper.AccoutMapper">
<insert id="save" parameterType="com.chaosbom.entity.Account">
insert into t_account(username,password,age) values(#{username},#
{password},#{age})
</insert>
</mapper>

实体对象和表

实体对象是mysql中表字段对应到java的类,通常在代码框架中被叫做entity。下面分别展示了java类和表结构。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
<!-- more -->
package com.chaosbom.entity;
import lombok.Data;
@Data
public class Account {
private int id;
private String username;
private String password;
private int age;
public Account(String username,String password,int age){
this.username=username;
this.password=password;
this.age=age;
}
public Account(int id,String username,String password,int age){
this.id=id;
this.username=username;
this.password=password;
this.age=age;
}
}

1
2
3
4
5
6
create table t_account(
id int primary key auto_increment,
username varchar(11),
password varchar(11),
age int
)

套路概述

本小节是总体认知。

各种mapper被配置到mybatis的配置文件 —> mybatis的xml配置文件 —> 被加载到SqlSession —> 提供各种mapper的对象,对象的行为等于操作数据库动作。

1自定义接口

AccountRepository.java 是定义entity实体行为的接口,行为的实现在对应的mapper中实现,方法名对应map中的id。

1
2
3
4
5
6
7
8
9
10
package com.chaosbom.repository;
import com.chaosbom.entity.Account;
import java.util.List;
public interface AccountRepository {
int save(Account account);
int update(Account account);
int deleteByID(long id);
List<Account> findAll();
Account findByID(long id);
}

2定义mapper

参考AccountRepository.xml中的内容。

创建接口口对应的 Mapper.xml,定义接口口方方法对应的 SQL 语句句。

MyBatis 框架会根据规则自自动创建接口口实现类的代理理对象。
规则:

  • Mapper.xml 中 namespace 为接口口的全类名。
  • Mapper.xml 中 statement 的 id 为接口口中对应的方方法名。
  • Mapper.xml 中 statement 的 parameterType 和接口口中对应方方法的参数类型一一致。
  • Mapper.xml 中 statement 的 resultType 和接口口中对应方方法的返回值类型一一致。

mapper是定义了被映射对象行为的文件。AccountRepository.xml(mapper)的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<?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.chaosbom.repository.AccountRepository">
<insert id="save" parameterType="com.chaosbom.entity.Account">
insert into t_account(username,password,age) values (#{username},#{password},#{age})
</insert>
<update id="update" parameterType="com.chaosbom.entity.Account">
update t_account set username=#{username},password=#{password},age=#{age} where id=#{id}
</update>
<delete id="delete" parameterType="long">
delete from t_account where id=#{id}
</delete>
<select id="findAll" resultType="com.chaosbom.entity.Account">
select * from t_account
</select>
<select id="findById" parameterType="long"
resultType="com.chaosbom.entity.Account">
select * from t_account where id = #{id}
</select>
</mapper>

mapper中的方法标签

  • namespace 通常设置为文文件所在包+文文件名的形式。
  • insert 标签表示执行行行添加操作。
  • select 标签表示执行行行查询操作。
  • update 标签表示执行行行更更新操作。
  • delete 标签表示执行行行删除操作。
  • id 是实际调用用 MyBatis 方方法时需要用用到的参数。
  • parameterType 是调用用对应方方法时参数的数据类型。
  • resultType是返回结果类型

3mybastisconfig中引用mapper配置

mybatisConfig.xml 是mybatis的配置文件。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE configuration PUBLIC "-//mybatis.org//DTD Config 3.0//EN"
"http://mybatis.org/dtd/mybatis-3-config.dtd">
<configuration>
<settings>
<!-- 打印SQL-->
<setting name="logImpl" value="STDOUT_LOGGING" />
</settings>
<environments default="dev">
<environment id="dev">
<!-- 配置jdbc事务管理-->
<transactionManager type="JDBC"></transactionManager>
<!-- 数据库连接池-->
<dataSource type="POOLED">
<property name="driver" value="com.mysql.cj.jdbc.Driver"/>
<property name="url" value="jdbc:mysql://localhost:3307/repeater?useUnicode=true&amp;characterEncoding=UTF-8"/>
<property name="username" value="root"/>
<property name="password" value="miang521"/>
</dataSource>
</environment>
</environments>
<!-- 注册各种mapper.xml -->
<mappers>
<mapper resource="com/chaosbom/repository/AccountRepository.xml"></mapper>
</mappers>
</configuration>

4调用用接口口的代理理对象完成相关的业务操作

下面展示一个启动的java类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.chaosbom;

import com.chaosbom.entity.Account;
import com.chaosbom.entity.Student;
import com.chaosbom.repository.AccountRepository;
import org.apache.ibatis.session.SqlSession;
import org.apache.ibatis.session.SqlSessionFactory;
import org.apache.ibatis.session.SqlSessionFactoryBuilder;

import java.io.InputStream;
import java.util.List;

public class MybatisProxyTest {
public static void main(String[] args) {
InputStream inputStream=MybatisProxyTest.class.getClassLoader().getResourceAsStream("mybatisConfig.xml");
//下面三行代码是使用mybatis的标准套路,先定义builder,builder读取配置,生成工厂,工厂提供db的链接
SqlSessionFactoryBuilder builder=new SqlSessionFactoryBuilder();
SqlSessionFactory factory=builder.build(inputStream);
SqlSession session=factory.openSession();
//获取接口的代理对象,动态代理
AccountRepository repository=session.getMapper(AccountRepository.class);
//findAll()方法是mapper中定义的,id=findAll
List<Account> reslut=repository.findAll();
for(Account account:reslut){
System.out.println(account.toString());
}
session.close();
}
}

解决连接查询

主要解决关联查询结果中字段的关系。mybatis是面向查询结果集来的。所以,可以是下面这种形式。主要在resultMap中搞定。

某mapper.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
<?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.chaosbom.repository.CustomerRepository">
<resultMap id="customerMap" type="com.chaosbom.entity.Customer">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<collection property="goods" ofType="com.chaosbom.entity.Goods">
<id column="gid" property="id"></id>
<result column="gname" property="name"></result>
</collection>
</resultMap>
<resultMap id="studentMap" type="com.chaosbom.entity.Student">
<id column="id" property="id"></id>
<result column="name" property="name"></result>
<association property="classes" javaType="com.chaosbom.entity.Classes">
<id column="cid" property="id"></id>
<result column="cname" property="name"></result>
</association>
</resultMap>
<select id="findCusGoodsByID" resultType="com.chaosbom.entity.Customer" parameterType="int" resultMap="customerMap">
select c.id,c.name,g.id as gid,g.name as gname from t_consumer as c,t_consumer_goods as cg,t_goods as g where cg.cid=c.id and cg.gid=g.id and c.id=#{id};
</select>
<select id="findByID" resultType="com.chaosbom.entity.Student" parameterType="int" resultMap="studentMap">
select s.id,s.name,c.id as cid,c.name as cname from t_student as s ,t_classes as c where s.id=#{id} and s.cid=c.id
</select>
</mapper>

mybatis逆向工程

mybatis需要程序员自己编写sql语句,mybatis官方提供逆向工程,可以针对\单表**自动生成mybatis执行所需要的代码(mapper.java、mapper.xml、pojo…),可以让程序员将更多的精力放在繁杂的业务逻辑上。

企业实际开发中,常用的逆向工程方式:由数据库的表生成java代码。逆向可以做成固定代码,直接用即可。这里不啰嗦了。

https://blog.csdn.net/qq_39056805/article/details/80585941

mybatis延迟加载

延迟加载也叫懒加载、惰性加载,使用用延迟加载可以提高高程序的运行行行效率,针对于数据持久层的操作,
在某些特定的情况下去访问特定的数据库,在其他情况下可以不不访问某些表,从一一定程度上减少了了 Java
应用用与数据库的交互次数。

查询学生生和班级的时,学生生和班级是两张不不同的表,如果当前需求只需要获取学生生的信息,那么查询学
生生单表即可,如果需要通过学生生获取对应的班级信息,则必须查询两张表。

不不同的业务需求,需要查询不不同的表,根据具体的业务需求来动态减少数据表查询的工作就是延迟加
载。

mybatis缓存

为什么加缓存

使用用缓存可以减少 Java 应用用与数据库的交互次数,从而而提升程序的运行行行效率。比比如查询出 id = 1 的对

象,第一一次查询出之后会自自动将该对象保存到缓存中,当下一一次查询时,直接从缓存中取出对象即可,无无需再次

访问数据库。

mybatis缓存分类

一级缓存

SqlSession级别,默认开启,并且不能关闭。

SqlSession对象中维护这一个HashMap用于储存换出数据,线程隔离。不同的SqlSession 之间缓存数据区域是互相不不影响。

如果 SqlSession 执行行行了了 DML 操作(insert、update、delete),MyBatis 必须将缓存清空以保证数据的准确。

二级缓存

Mapper级别,默认关闭,可以开启。

多个sqlsession使用同一个mapper的sql语句操作数据库,得到的数据会存在二级换出区,同样使用的是HashMap存储,线程共享。二级缓存的作用域是mapper下的同一个namespace。二级缓存优先级高于一级缓存。

config中开启

1
2
3
4
5
6
7
8
<settings>
<!-- 打印SQL-->
<setting name="logImpl" value="STDOUT_LOGGING" />
<!-- 开启延迟加载 -->
<setting name="lazyLoadingEnabled" value="true"/>
<!-- 开启二级缓存 -->
<setting name="cacheEnabled" value="true"/>
</settings>

mapper中配置二级缓存

1
2
3
4
5
6
7
8
<cache type="org.mybatis.caches.ehcache.EhcacheCache">
<!-- 缓存创建之后,最后一一次访问缓存的时间至至缓存失效的时间间隔 -->
<property name="timeToIdleSeconds" value="3600"/>
<!-- 缓存自自创建时间起至至失效的时间间隔 -->
<property name="timeToLiveSeconds" value="3600"/>
<!-- 缓存回收策略略,LRU表示移除近期使用用最少的对象 -->
<property name="memoryStoreEvictionPolicy" value="LRU"/>
</cache>

二级缓存的问题

高并发下,缓存机制带来的脏读问题。

mybatis动态SQL

使用用动态 SQL 可简化代码的开发,减少开发者的工工作量量,程序可以自自动根据业务参数来决定 SQL 的组
成。动态sql是在mapper中添加不同标签来实现。

  • if标签

  • where标签

  • choose、when标签

  • trim标签

  • set标签

  • foreach标签

    一个例子,其他的用法用时再细纠。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    <select id="findByAccount" parameterType="com.southwind.entity.Account"
    resultType="com.southwind.entity.Account">
    select * from t_account
    <where>
    <if test="id!=0">
    id = #{id}
    </if>
    <if test="username!=null">
    and username = #{username}
    </if>
    <if test="password!=null">
    and password = #{password}
    </if>
    <if test="age!=0">
    and age = #{age}
    </if>
    </where>
    </select>

有价值的链接

这篇读书笔记是《Java多线程编程核心技术》图书的最后一篇。由于写笔记的时候已经读完了整本书,留下了一个大致的印象——适合做多线程的入门读物,所以在读完后感觉缺点什么东西,顺手就打开了另一本《Java并发编程的艺术》,瞬间感觉当年书买得十分的合理,《Java并发编程的艺术》虽然没有开始读,但是大致看了几页,感觉这本书还是要深入一些,更加贴近原理,知识的密度要高很多。

第3章 线程间通信

这一章基本围绕“wait等待/notify通知” 机制来描述线程之间通信的方式。

wait/notify

其核心思想是处理好锁的获取,锁的释放,唤醒(本质是改变线程自己的状态)的关系。

每个锁都有两个队列,一个就绪,一个阻塞。就绪是要需要锁的(可参与锁竞争),阻塞是不需要锁的(被其他事情中断而不能参与锁的争夺,notify就是改变这个队列中的线程的状态,使其进入就绪状态)

某线程调用的lock对象的wait()方法,线程释放锁,进入waiting状态(线程的等待队列);

其他线程的lock对象调用notify()或notifyall()方法,则随机或全部讲waiting该锁的线程设置回runnable可执行状态,同时线程会在完成自己代码的执行后,释放自己占用的lock(注意不是notify动作的时候释放)。等待队列中的线程则被cpu随机调用执行。

这里要题外话,书上描述“如果线程抢占到cpu资源…………”,这个描述很容易让新手误解线程是主动的,实际上并不是,是线程自己的状态配置被其他获取到cpu资源的线程改变了,然后被cpu调用到了才对。

wait(long)可以加时间参数,等带long时间看看有没有被唤醒,超过long就自动唤醒。

使用wait/notify,需要避免混乱:如过早通知、等待条件发生改变

生产/消费者模式

生产者和消费者数量在{1,N}的笛卡尔积的组合,如何处理好同步。主要是利用wait/notify的技巧。

还介绍了以下管道进行线程间的通信。这个之前了解比较少就专门记录一下。

  • PipedInputStream 和 PipedOutputStream,通过各自对象的connect(stream)方法建立进和出通道的联系
  • PipedReader 和PipedWriter,同上

线程的join方法

线程若需要其他线程等待自己线程结束,可以使用的方法。为什么要等?比如等子线程执行后返回值。是被等待的线程调用join()方法来阻塞等待线程。join()具有使线程排队运行的作用,与synchronized的区别:join内部使用的wait()方法进行等待,而synchronized是使用的对象监视器做同步。

join(long) 同wait(long)。

join(long) 和sleep(long) 区别。锁释放阻塞和和锁持有等待(阻塞)。

阅读全文 »

题记

在B站上看到马士兵老师讲解美团研发死亡七连问的视频,讲课中听到马老师的一句鸡汤,“往深了学,往宽了学”,被马老师深厚的技术功底和探求精神折服。遂,翻出了买了很久但是还没有读的《java多线程编程核心技术》和《java并发编程的艺术》,选择了简单入门的《java多线程编程核心技术》读了起来。之前买了没有去看,因为觉得并发编程对我来说太深了,我还没到那个层次,所以书都没有打开过。这次在家待业,学了一些基础的jvm原理,不再恐惧了。翻出来,一天看了2章,并没有觉得看不懂。恩,我可能是低估了自己能力。所以计划4天把书看完,并整理出笔记。先看书,再行笔记。看书过程中,如果有看不懂或理解不上来的,直接就敲了代码了。所以本笔记,没有代码。

并发问题的来源

本节内容纯属自编自导,非教程内容,不做质保。

最根本的原因是cpu运算速度远超其他存储设备,每一次脉冲就是它的一次总线宽度的二进制信号变换,变换的规则都烙印在了硬件当中,为了便于控制,形成了很多叫指令的命令(多次脉冲组合),有些指令是原子的不可再分,有些则可以再分开(不知道描述是否准确)。

进程(线程)和CPU的关系是,被CPU执行,进程和线程是被动的,它要达到什么目的,只能写到自己身上,安静的等着CPU来调度的时候由CPU来解析后被执行。个人觉得理解这点很重要。

人们为了挖掘计算机最大的算力,而设计了一套多线程机制,多个线程一起干活。多线程之间存在“公共资源”的情况。多线程的运行机制大致是,以java为例,代码编译成字节码,加载到jvm成为指令,指令被jvm翻译给cpu执行。这些个线程中的代码指令集合(编码后最终的底层指令)就开始等待cpu的时间片来宠幸自个。但是对于这些个指令来说,它是没有权利控制CPU什么时候来找你的。这就导致了,虽然线程内部的指令执行是线性的,但是多线程和线程之间的指令可就不是有顺序的,它们之间彼此交叉,是随机的,这种随机推进一步就是线程告知CPU的信息也是随机的。既然出现了顺序的随机性,在“公共资源”的情形下,就需要同步机制来控制线程的执行顺序执行。至于为什么要同步……恩,哲学问题。线程之间同步信息方可行为达预期。

一句话,时间片分配的随机性、共同资源需要顺序执行是并发问题的主要来源。高并发下,只要高级语言中的代码被转换成的指令不是原子的指令,就可能出现线程的同步问题。

第1章 多线程技能

介绍了进程线程的关系,入门级的,就不记了。以后会深化理解。

多线程的使用姿势

怎么申明多线程。

  • extend Thread 覆盖run方法
  • implement Runnable 实现run方法

Thread的构造法中支持实现了Runnble接口的类,恩,面向抽象的体现。

一些常见方法:

  • Thread.currentThread()可以获取当前线程。
  • isAlive() 判断线程是否处于活动状态
  • Thread.sleep() 休眠(暂停执行)当前线程,不会让出锁
  • getId()获取线程的唯一标识

停止线程需要说的。

阅读全文 »

计划覆盖一些常见的框架,首选spring boot,在这之前先学习spring基础原理。大致了解后再进入spring boot。所以,spring去学习的时候不会过于纠结太深入的内容。大致了解原则,这篇内容就是这套逻辑下的笔记内容。看了2套视频,前后花了6天时间。

以下内容结合了个人理解整理而成,不保证描述完全准确。

初识Spring

面向接口编程、解耦。私有变量只申明,但不new对象,变量用它的接口。

Spring解决企业级开发的痛点,数不清的类之间的相互关系,委托给Spring来管理。用个术语:装配。

Bean实际上是Spring中负责加载具体业务对象的类。Spring提供了装配类对象实例的机制。这套机制是IOC\AOP的思想,对应的具体实现是DI(依赖注入)和java的注解实现的AOP和aspectJ实现的AOP。

在学习spring过程中,突发灵感,认识到计算机世界中,context是多么的重要。context在这里我表征软件执行的环境、输入条件、依赖等前置因素。所有的代码,都是在进程开始启动过程中,完成初始化、环境构造、代码执行这么一套流程的。大体,这是目前我所理解的软件的抽象。

Spring配置类注解作为入口,把类加载到运行时中(默认是单例模式,可控制),类和类之间的组合关系,实现相同接口的接口实现之间的如何区分。都提供了注解机制。

注入和装配的套路

入门级的套路:xml配置和注解基本上在自己可控源码的化效果是等价的。在第三方的源码上,利用xml方式。

Spring的在做注入时,秉着一条“傻瓜”原则,只要spring的容器中某类的实例只有一个,那么只要你告诉(配置xml和注解)spring
那么,就会自动去绑定。如果有多个,设定必要的标识(名称、顺序等)区分也就完成了绑定工作。

注解的套路

下面的注解是入门级的示意。

1
2
3
4
5
6
7
8
9
10
11
12
13
#需要被Spring加载标识
@Component @Controller @Service @Repository

# 解决歧义(让引擎识别相同接口不同的实现对象,或者相同类的不同bean,靠名称或默认类名首字母小写)
@Autowired(required=true)
#相同接口的区分手段之一
@Qualifier
# java原生的区别手段
@Resource

# 引入外部类不方便使用Componet等时,可以加注解
# 被加了备注的方法,会自动去运行时环境中查找参数涉及的类的实例
@Bean
阅读全文 »

本文是学习Spring框架的副产品。Spring中的AOP涉及动态代理的原理。

什么是代理

定义:给目标对象提供一个代理对象,并由代理对象控制对目标对象的引用;

目的:

  • 通过引入代理对象的方式来间接访问目标对象,以防止直接访问目标对象给系统带来的不必要的复杂性;
  • 通过代理对象对原有业务进行增强

代理设计模式

https://www.runoob.com/design-pattern/proxy-pattern.html

静态代理不能解决代码冗余的问题。一般不推荐静态代理(代理的关系用代码直接定义,代理和被代理需要有相同的接口,被代理作为代理对象的成员变量)。

jdk机制的动态代理

动态代理有以下特点:

  • 代理对象,不需要实现接口
  • 代理对象的生成,是利用JDK的API,动态的在内存中构建代理对象(需要我们指定创建代理对象/目标对象实现的接口的类型)

动态代理的实现方案

  • jdk代理,通过和目标实现相同接口保证功能一致
  • cglib代理(第三方cglib库中的一套api),通过继承保证功能一致

主要涉及:

1
2
3
4
// 静态方法
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler h )
// 接口
public interface InvocationHandler {....}
阅读全文 »

我喜欢追本溯源,渴望真理,而不至被表象迷惑。

这篇文章未写完。可能计划读一下《计算机的数学基础》这本书再写。

计算机的数学基础

形式语言与自动机理论、可计算理论、逻辑学和程序设计理论,都是研究计算模型的。它们之间也是相互关联的,共同构成了现代计算机科学技术的理论基础。这些理论都是属于数学学科的。

形式语言与自动机理论、可计算理论和逻辑学的研究都始于20世纪初叶,特别是20世纪30年代的数学家Church(邱奇)、GMel(哥德尔)、Kleene(克林)、Post(波斯特)以及Turing(图灵)等人的杰出工作催生了现代电子数字计算机的硬件和软件的诞生。

程序设计理论的研究相比则要迟一些,是20世纪后半叶现代电子数字计算机以及程序设计语言和软件诞生之后的事情了。它是专门研究程序设计语言和程序设计方法的数学理论。这些工作对于计算机科学的实践和理论的发展有着深远的影响。比如,图灵机模型就被证明是现代电子数字计算机的理论模型。这些先驱者的工作在今天看来似乎是很平常的,它们的思想渊源甚至并不为今天众多的计算机的使用者所知道。但是这些先驱者的工作确实是应该被那些从事计算机科学技术的工作者们所熟悉、所掌握的。

语言和逻辑

人类由猿进化成人,成为灵长类的智慧生物,是进化的奇迹。语言在数百万年的进化进程中,在人类这台大自然打造的“生物机器”中,也不断的进化,相互促进,形成目前人类拥有的——自然语言。

语言,我认为它的本质是承载信息的载体。它可以装载情感、请求、命令、陈述等。

自然语言是丰富而复杂的,同一句话,不同的语境、时间、预期所要传递的信息是多样的。这里面很多段子就不一一罗列了。根本原因是自然语言属于人类,它适应人类文明。自然语言的信息传递,依赖于外界环境。语言和它所传递的信息之间,没有一对一的关系,就像算命先生算命,用些模棱两可的话说给你听,还有些星座算命也是一样的,听、读的人接受信息的背景差异,导致相同语言传递的信息千差万别。

语言的诞生,促进了文明发展,萌生了逻辑、推理。先哲用语言讲理,随着理讲得越多,人们发现要讲好道理,首先要做好陈述。没有可靠的陈述作为前提,再完美的论证过程也只是空中楼阁。因此逻辑学逐渐放大研究视野,将语法和词汇承载的信息也纳入到研究范畴中。他们(我不知具体是哪些人)得出:人类使用的陈述句、疑问句、感叹句、祈使句,在着重考虑陈述和论证,就只需要陈述句了。小学学过的,各种句型互转就明白。比如:“你是谁?”,陈述句为:“我希望知道你是谁”。感叹句:“好美的女子!”,陈述句:“女子的美丽让我感叹”。

逻辑、推理进步,让自然语言作为信息传递载体做了一次丢弃,仅留下陈述句。本身语言其实就是一种和承载信息间的“指代”和“映射”。接下来对陈述句的组成部分进行拆解,仅仅做简单拆解。

代词。所谓代词就是用于代替对象的词汇,替代具体的对象出现在语句中并表示被代替的对象。比如,“月球绕地球公转,它的自转周期和地球自转周期相同”。“月球”指代我们想指代的那个对象,“它”指代月球,代词可以是指代的指代,代词的作用和语境有关。

名词。词典中约定词汇含义的方法是用一个固定句式的语句来描述它。比较简单的做法是用“某词是什么意思”的句式把词汇的含义表达出来。

谓词。一类可以将语句中其他成员建立起联系的词。“我喜欢你“,“我在写”,“我写文章”。(个人理解,可能不当)。

接下来讨论语言中的逻辑。单纯的判断你一句话是否是真或假,是没有固定结论的,因为结论依赖于说话的场景。所以,在纯逻辑层面,我们去讨论真假,就只关注语言内部的自恰性了。所以,论述的起点,它必然是整个推理的基石。在没有任何已知前提的情况下,逻辑不能给我们任何新的知识。因此必须在已经有一些已知信息的情况下,我们才能运用逻辑。题外话,基石在很多科幻电影,比如“西部世界”中很多接待员的底层都一个他们行为的基石概念。

先哲们逐步定义了一门叫数理逻辑的学科。 其研究对象是对证明和计算这两个直观概念进行符号化以后的形式系统。

https://baike.baidu.com/item/%E8%AE%A1%E7%AE%97%E6%9C%BA%E7%A7%91%E5%AD%A6%E7%9A%84%E6%95%B0%E5%AD%A6%E5%9F%BA%E7%A1%80/866204?fr=aladdin

阅读全文 »

本文是结合写于2015年的博客jenkins源码分析获取脉络,结合自己的研究完成,较原文有所拓展和深入。

jenkins框架

architecture_jenkins

jenkins的Model对象

jenkin(实际是传承Hudson的)Model对象jenkin平台的基石,它们hold住了某一个(job、project、executor、user、buildable item、test result)的数据和状态。

每个Model对象可以和多个views绑定,view使用了Jelly来渲染HTML和对象。

Model的可执行性是通过绑定Actions对象到Model。

Model如是描述对象存在时,是通过绑定Descriptor对象到Model。

每个Model对象和一个URL对象绑定。
Stapler通过类似JSF表达式的方式来解决URL和Model Object的绑定问题。Stapler同时处理一个model和URL,然后根据object计算URL,一直重复这个动作,直到命中某个静态资源、可执行方法、视图(jsp、jelly、groovy等)。

命中可执行方法举例:

1
2
3
4
5
6
Scenario: browser sends "POST /project/jaxb/testResult HTTP/1.1"

evaluate(<root object>, "/project/jaxb/testResult")
-> evaluate(<root object>.getProject("jaxb"), "/testResult")
-> evaluate(<jaxb project object>, "/testResult")
-> evaluate(<jaxb project object>.getTestResult())

命中视图举例:

1
2
3
org.jvnet.hudson.project.testResul -> /org/jvnet/hudson/project/testResult/index.jelly

命中之后,response.forward(this,"/org/jvnet/hudson/project/testResult/index.jelly",request)

jenkins用了stapler

阅读全文 »