涉及的知识点:自定义注解反射、文件操作

IOC的加载顺序

    1. 扫描bean
    2. 注册bean
    3. 注入bean

实现思路:

    将指定路径下的所有类保存到特定的List中,再去读取该List,找到特定的注解(@Controller、@Service),通过反射生成对象再将其保存到Map中,再从该Map中读取特定的注解(@Qualifier),对需要的Field注入bean。

目录结构:

├── annotation
│   ├── Controller.java
│   ├── Qualifier.java
│   ├── RequestMapping.java
│   └── Service.java
├── controller
│   └── MyController.java
├── service
│   ├── MyService.java
│   └── impl
│       └── MyServiceImpl.java
└── servlet
    └── DispatcherServlet.java

- 阅读剩余部分 -

2018-08-13 01:38 未完待续


操作环境:CentOS 7.2

安装Git

yum install git

以下目录均相对于/opt/gitRepo

Git基本操作

初始化gitRepo目录为Git管理的仓库

git init
创建readme.txt文件并增加内容

vim readme.txt

this is a txt file.

增加文件到Git仓库,即让Git管理该文件,只有仓库中的文件才受Git管理,可以一次增加多个文件 git add 1.txt 2.txt

git add readme.txt

提交文件到本地仓库,-m后面是提交说明

git commit -m 'commit explain'

查看工作区stage状态

- 阅读剩余部分 -

最近女朋友要准备软件测试的面试,看到了一个SQL的面试题,找我要答案,我觉得挺有意思,特分享出来。

题目要求结合2张基本表的内容,按要求输出需要的结果。

基本表A:

user_idname
1000张三
1001李四

基本表B:

key_iduser_idresult
00011000
00021001
00031001
00041000
00051000

输出的结果表C

姓名
张三21
李四11

解法一:观察结果表可以看到胜负数通过B表的result可以推到出来,姓名可以用user_id暂时替代,中间表B_result如下

- 阅读剩余部分 -

本文基于Centos 7.2 jdk1.8.0_161apache-tomcat-8.0.52solr-6.6.3

Solr界面介绍

Solr后台地址:http://127.0.0.1:8080/solr/index.html

solr_dashboard.jpg

Dashboard仪表盘:Solr版本信息、JVM、JVM-Memory 等

Logging:Solr运行日志

Core Admin索引库管理:包括创建coreAdd Core、卸载Core Unload、重新加载配置文件reload、优化Optimize

Core SelectorCore核心选择器:概况Overview、分词Analysis、查询Query、数据导入Dataimport

Core Selector的内容在后面再做详细介绍,这里只做简单的认知。

创建Solr Core

Solr home的路径为/opt/solr_home

mkdir -p test/conf

- 阅读剩余部分 -

     Java提供了一种序列化机制,可以将一个对象的类型和数据等信息写入到文件(序列化作用于对象),这个机制就是序列化机制。之后可以通过反序列化机制将其读取出来并用其新建对象,该过程基于JVM,因此可以在一个平台上序列化之后在另一平台上反序列化出对象。有时候因业务需要(如银行卡号、密码等敏感信息)并不会将所有的信息都序列化,这时需要使用transient关键字标识该属性不会序列化到文件中。

User类:实现了Seriazable

一个类要被序列化必须满足2个条件:

1、该类必须实现 java.io.Serializable对象:ArrayList、HashMap都实现了都可以被序列化

2、该类的所有属性都可以被序列化,如果不可被序列化则该属性必须用transient注明是短暂的

import java.io.Serializable;
/**
 * Created by m@zhangguoli.cn on 07-11-011 <br >
 */
public class User implements Serializable {

    public String uuid;
    public String username;
    public transient String password;
}

序列化

Java序列化后生成的文件后缀为.ser

- 阅读剩余部分 -

Solr官网:http://lucene.apache.org/solr/

0、环境及各文件下载地址

1、 CentOS 6.5 X64

2、 jdk-8u161-linux-x64.tar.gz

http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
http://cdn.zhangguoli.cn/solr/jdk-8u161-linux-x64.tar.gz

3、 apache-tomcat-8.0.52.tar.gz

https://archive.apache.org/dist/tomcat/tomcat-8/
https://archive.apache.org/dist/tomcat/tomcat-8/v8.0.52/bin/apache-tomcat-8.0.52.tar.gz

4、 solr-6.6.3.tgz

http://lucene.apache.org/solr/downloads.html
http://cdn.zhangguoli.cn/solr/solr-6.6.3.tgz

1、JDK安装及配置

参考 CentOS6.5 安装JDK 、Tomcat

2、Solr环境搭建及配置

1、解压apache-tomcat-8.0.52.tar.gzsolr-6.6.3.tgz

- 阅读剩余部分 -

学习JDK的动态代理前需要了解静态代理的实现,假设我们有一个接口Moveable,一个类BMW,通过静态代理的方式获取汽车行驶的时间。

静态代理

(1)Moveable接口,有个move()方法

package guoli.proxy;
public interface Moveable {
    void move();
}

(2)类BMW实现了Moveable接口

- 阅读剩余部分 -

java.sql下的StatementPreparedStatementCallableStatement是用来执行SQL查询的API。其中Statement用于执行普通查询,PreparedStatement用于执行参数化查询,CallableStatement则用于存储过程。他们之间的继承关系:PreparedStatement extends StatementCallableStatement extends PreparedStatement

本文主要介绍的是PreparedStatement的简单使用、相比Statement的优势,以及PreparedStatement的局限性。

PreparedStatement示例

String url = "jdbc:mysql://127.0.0.1:3306/dbname";
//获取一个连接
Connection conn = DriverManager.getConnection(url, "username", "password");
//PreparedStatement 为预编译对象
PreparedStatement pst = conn.prepareStatement("select uuid from test limit ?");
pst.setInt(1, 1);
//结果对象
ResultSet result = pst.executeQuery();
while (result.next()) {
    System.out.println(result.getString("uuid"));
}
//依次关闭
result.close();
pst.close();
connection.close();

PreparedStatement优势

- 阅读剩余部分 -

本文基于jdk1.9,且只分析了put()的实现

initialCapacity 初始化容量
loadFactor 负载因子

HashMap底层基于数组+链表数组+红黑树实现


put(K key, V value)

Object key;
Object value;
static final int hash(Object key) {
    int hash;
    if(key == null){
        hash = 0;
    }else{
        int h = key.hashCode();
        hash = h^(h>>>16);
    }
}
 public V put(K key, V value) {
    return putVal(hash(key), key, value, false, true);
}
final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
               boolean evict) {
    Node<K,V>[] tab; 
    Node<K,V> p;
    int i;
    tab = table;
    int n = tab.length; //HashMap的长度/大小
    i = (n-1) & hash;//计算所在的数组的下标index
    p = tab[i]; //+++保存所在位置的已经存在的Node数据+++
    if ((tab == null || n == 0){
        tab = resize();//调整Node大小,扩容每次增加一倍
        n = tab.length;
    }
    if ((p == null){//如果要插入的位置Node为null,则在此处直接增加Node
        tab[i] = newNode(hash, key, value, null);//<=new Node<>(hash, key, value, next);
    }
    else {//
        Node<K,V> e; //【代表了?】
        K k = p.key;
        if (p.hash == hash && ((k == key || (key != null && key.equals(k)))){//【?】
            e = p;
        }
        else if (p instanceof TreeNode)//【使用treeNode保存了,详细代码后面再看】
            e = ((TreeNode<K,V>)p).putTreeVal(this, tab, hash, key, value);
        else {
            for (int binCount = 0; ; ++binCount) {//在index位置循环链表,在链表的最后插入新数据
                e = p.next;
                if (e == null) {//++ 最后一个Node
                    p.next = newNode(hash, key, value, null);//将新Node插入到此处链表的最后
                    if (binCount >= TREEIFY_THRESHOLD - 1) // -1 for 1st   TREEIFY_THRESHOLD = 8 
                        treeifyBin(tab, hash);//链表长度大于8则转为红黑树TreeNode
                    break;
                }
                k = e.key;
                if (e.hash == hash && (k == key || (key != null && key.equals(k))))//【?】
                    break;
                p = e;
            }
        }
        if (e != null) { // existing mapping for key
            V oldValue = e.value;
            if (!onlyIfAbsent || oldValue == null)//如果onlyIfAbsent为true,则不更新此处的值;
                e.value = value;
            afterNodeAccess(e);//Node访问之后执行的操作,更新链表,把最近访问的放到最后
            return oldValue;
        }
    }
    ++modCount;
    if (++size > threshold)
        resize();//调整大小
    afterNodeInsertion(evict);//节点插入之后执行的操作
    return null;
}

本文基于:CentOS release 6.5 (Final)

注意SMTP使用默认端口25和加密端口465在配置上的区别

安装

yum -y install mailx

配置发送人信息

vim /etc/mail.rc 在最后增加:

set from=yourEmailAddress
set smtp=smtpAddress
set smtp-auth-user=yourEmailAddress
set smtp-auth-password=youPassword
set smtp-auth=login

使用三种方式发送邮件

  • 命令行: mail -s "theme" addressee,回车后输入内容按Ctrl+D发送邮件.
  • 管道符: echo "mail main content" | mail -s "theme" addressee
  • 文件内容作为邮件内容: mail -s "theme" addressee < /tmp/t.txt

thme是邮件标题,addressee收件人地址


在搜索CentOS上发送邮件时,大部分都是上面的流程,的确在部分机器是测试成功的,唯独ECS不成功,后来了解到ECS默认关闭25端口。


使用SSL的方式发送邮件

- 阅读剩余部分 -