FreeBSD 11设置Tunnelbroker IPv6隧道

最近把热备的vps迁移到了阿里云国际版$4.5刀上面. 由于阿里云本身不支持原生IPv6, 只能使用tunnelbroker提供的隧道来实现IPv6的支持. FreeBSD 11的API和之前版本有一些不同,因此写一篇blog来记录官方推荐的IPv6隧道的配置.

 

以下为tunnelbroker的信息页

请在/etc/rc.conf最后加入下列配置, 请根据自己的IPv6信息修改配置.

# IPv6 Tunnel Client
ipv6_activate_all_interfaces="YES"
ifconfig_vtnet0_ipv6="inet6 IPv6地址 prefixlen 64"
cloned_interfaces="gif0"
ifconfig_gif0="tunnel 本机IP 隧道服务器IPv4地址"
ifconfig_gif0_ipv6="inet6 IPv6地址 IPv6网关IP prefixlen 128 mtu 1480"
ipv6_defaultrouter="-iface gif0"

重启网络和路由

service netif restart && service routing restart

现在你的IPv6地址应该就可以使用了.

Linux下创建Patch的方法

当在Linux下修改了某个文件(夹)之后,如果需要把修改的部分分享出去,可以使用diff命令来创建patch(补丁)文件.

在使用diff命令创建patch之前,我们需要修改之前的原始文件,和修改过的新文件.

当为一个文件创建patch的时候可以使用以下代码:
diff -Naru file_orig.c file_updated.c > file.patch

其中

  • -N 将缺失文件视为空
  • -a 将所有文件视为文本文件
  • -r 递归比较所有子文件夹
  • -u 输出行数(默认 3)行

 

当需要为整个文件夹创建patch的时候可以使用以下代码:
diff -crB dir_orig dir > dfile.patch

其中

  • -c 输出行数(默认 3)行
  • -r 递归比较所有子文件夹
  • -B 忽略连续的换行符

当你需要应用这个patch的时候可以运行
patch -p1 --dry-run < file.patch
其中参数-p[n]中的n值为需要跳过的目录数.

以/usr/src/linux为例:

若-p0就是不跳过任何目录,

-p1将跳过/,得到usr/src/linux,

-p2将跳过/usr,得到src/linux

绝大多数情况下这个值应该为1.

 

删除–dry-run当你满意输出到屏幕上的结果.

FreeBSD 11.1下使用DHCPv6

因为FreeBSD base包中带的dhclient不支持IPv6, 所以FreeBSD原生不支持DHCPv6. 但是如果我们可以使用dual-dhclient来让FreeBSD支持DHCPv6.

 

通过Pkg安装dual-dhclient

pkg install dual-dhclient

 

在/etc/rc.conf中加入以下配置来启用dual-dhclient

ipv6_activate_all_interfaces="YES"
dhclient_program="/usr/local/sbin/dual-dhclient"
ifconfig_DEFAULT="DHCP accept_rtadv"

 

重启网络

service netif restart

 

稍等片刻即可成功获取到IPv6地址.

参考: https://forums.freebsd.org/threads/60168/

Spring 使用 AOP+注解 来记录方法执行时间

一直以来都知道Spring支持一种叫做面向切面编程(AOP)的东西,但是一直都没有自己尝试使用过. 直到最近为了Debug方法,记录使用时间猛然发现AOP正好适合使用在这个场景下.为了灵活的使用AOP,我选择了使用注解来作为标记,当某个特定的注解被使用的时候将会自动触发这个切面.

1.注解的编写

package org.jzbk.rssplus.aspect.annotation;

import java.lang.annotation.*;

/**
 * Created by Kotarou on 2017/1/11.
 */
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Timed {
    boolean displayArgs() default false;
}

将注解设置为运行时RetentionPolicy.RUNTIME, 在编译时不会丢失这个注解信息.

设置注解主体为方法和类.

注解内部保存一个displayArgs的boolean变量,用于判断是否输出传入参数.

 

2. 编写AOP类

package org.jzbk.rssplus.aspect;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.Signature;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.jzbk.rssplus.aspect.annotation.Timed;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;

/**
 * Created by Kotarou on 2017/1/11.
 */
@Aspect
@Component
public class TimedAOP {
    final private Logger logger = LoggerFactory.getLogger(getClass());

    @Pointcut("@annotation(org.jzbk.rssplus.aspect.annotation.Timed) || @target(org.jzbk.rssplus.aspect.annotation.Timed)")
    public void annotationProcessor() {
    }

    @Pointcut("execution(public * org.jzbk.rssplus..*.*(..))")
    public void publicMethod() {
    }

    @Around(value = "publicMethod() &amp;&amp; annotationProcessor()")
    public Object count(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
        final String methodName = proceedingJoinPoint.getSignature().getName();

        Long startTime = System.currentTimeMillis();
        Object result = proceedingJoinPoint.proceed();
        Long finishTime = System.currentTimeMillis();

        Signature signature = proceedingJoinPoint.getSignature();
        String[] packageName = signature.getDeclaringTypeName().split("\\.");
        StringBuilder stringBuilder = new StringBuilder();

        for (int i = 0; i &lt; packageName.length; ++i) {
            if (i &lt; packageName.length - 1) {
                stringBuilder.append(packageName[i].substring(0, 1));
            } else {
                stringBuilder.append(packageName[i]);
            }
            stringBuilder.append(".");
        }

        logger.info("Executing: " + stringBuilder + signature.getName() + " took: " + (finishTime - startTime) + " ms");


        Method method = ((MethodSignature) proceedingJoinPoint.getSignature()).getMethod();

        if (method.getDeclaringClass().isInterface()) {
            method = proceedingJoinPoint.getTarget().getClass().getDeclaredMethod(methodName, method.getParameterTypes());
        }

        // 方法上的注解优先级比类上的注解高,可以覆盖类上注解的值
        Timed timed = null;
        if (method.isAnnotationPresent(Timed.class)) {
            //处理方法上的注解
            timed = method.getAnnotation(Timed.class);
            if (timed.displayArgs()) {
                logArgs(proceedingJoinPoint.getArgs());
            }
        } else {
            //处理类上面的注解
            Object target = proceedingJoinPoint.getTarget();
            if (target.getClass().isAnnotationPresent(Timed.class)) {
                timed = target.getClass().getAnnotation(Timed.class);
                if (timed.displayArgs()) {
                    logArgs(proceedingJoinPoint.getArgs());
                }
            }
        }

        return result;
    }

    private void logArgs(Object[] args) {
        StringBuilder stringBuilder = new StringBuilder();

        for (int i = 0; i &lt; args.length; ++i) {
            stringBuilder.append("[");
            stringBuilder.append(i);
            stringBuilder.append("]: ");
            stringBuilder.append(args[i].toString());

            if (i &lt; args.length - 1) {
                stringBuilder.append(", ");
            }
        }

        if (!stringBuilder.toString().isEmpty())
            logger.info("Argument List: " + stringBuilder);
        else
            logger.info("Argument List: Empty");
    }
}

 

AOP的切入点为使用了Timed的方法或者类.

方法上面的注解优先级比类上面的高,可以在方法上使用注解来覆盖掉类上注解的值.

 

演示:

在类上面增加注解,并设置displayArgs为true

 

在某个方式上覆盖注解冰将displayArgs设置为false

 

运行tomcat,查看日志

 

结果和期望中的一样.