月度归档:2020年04月

JDK1.6报错”the trustAnchors parameter must be non-empty”解决方案

如果您使用 Mac OSX 自带的 JDK 1.6 进行加解密相关操作的时候,报了如下错:

java.security.InvalidAlgorithmParameterException: the trustAnchors parameter must be non-empty

如果你本地安装了其它 Oracle 官方的 JDK,可以先删除原来的无用 3 个软链,然后将这三个文件指向 JDK 1.7 或者 JDK 1.8 的。

cd /Library/Java/JavaVirtualMachines/1.6.0_65-b14-462.jdk/Contents/Home/lib/security
rm -f cacerts trusted.libraries blacklist
sudo ln -s /Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/security/cacerts cacerts
sudo ln -s /Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/security/trusted.libraries trusted.libraries
sudo ln -s /Library/Java/JavaVirtualMachines/jdk1.8.0_152.jdk/Contents/Home/jre/lib/security/blacklist blacklist

 

Java静态代理动态代理总结

代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

简言之,代理模式就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式。

代理模式UML类图

总结

静态代理实现较简单,只要代理对象对目标对象进行包装,即可实现增强功能,但静态代理只能为一个目标对象服务,如果目标对象过多,则会产生很多代理类。

JDK动态代理需要目标对象实现业务接口,代理类只需实现InvocationHandler接口。

动态代理生成的类为 lass com.sun.proxy.$Proxy4,cglib代理生成的类为class com.cglib.UserDao$$EnhancerByCGLIB$$552188b6。

静态代理在编译时产生class字节码文件,可以直接使用,效率高。

动态代理必须实现InvocationHandler接口,通过反射代理方法,比较消耗系统性能,但可以减少代理类的数量,使用更灵活。

cglib代理无需实现接口,通过生成类字节码实现代理,比反射稍快,不存在性能问题,但cglib会继承目标对象,需要重写方法,所以目标对象不能为final类。

Java设计模式之动态代理CGLib版

代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

简言之,代理模式就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式。

代理模式UML类图

动态代理CGLib版

cglib is a powerful, high performance and quality Code Generation Library. It can extend JAVA classes and implement interfaces at runtime.

cglib (Code Generation Library )是一个第三方代码生成类库,运行时在内存中动态生成一个子类对象从而实现对目标对象功能的扩展。

cglib特点

1、JDK的动态代理有一个限制,就是使用动态代理的对象必须实现一个或多个接口。如果想代理没有实现接口的类,就可以使用CGLIB实现。

2、CGLIB是一个强大的高性能的代码生成包,它可以在运行期扩展Java类与实现Java接口。它广泛的被许多AOP的框架使用,例如Spring AOP和dynaop,为他们提供方法的interception(拦截)。

3、CGLIB包的底层是通过使用一个小而快的字节码处理框架ASM,来转换字节码并生成新的类。不鼓励直接使用ASM,因为它需要你对JVM内部结构包括class文件的格式和指令集都很熟悉。

cglib与动态代理最大的区别

1、使用动态代理的对象必须实现一个或多个接口

2、使用cglib代理的对象则无需实现接口,达到代理类无侵入。

使用cglib需要引入cglib的jar包,如果你已经有spring-core的jar包,则无需引入,因为spring中包含了cglib。

CGLib的Jar包Maven依赖

<!-- https://mvnrepository.com/artifact/cglib/cglib -->
<dependency>
    <groupId>cglib</groupId>
    <artifactId>cglib</artifactId>
    <version>3.3.0</version>
</dependency>

动态代理CGLib版代码示例

AccountDao接口类

package com.github.xuchengen.proxy.statics;

/**
 * 账户表数据访问层接口
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 2:03 下午
 */
public interface AccountDao {

    /**
     * 保存
     */
    void save();

}

AccountDaoImpl接口实现类

package com.github.xuchengen.proxy.statics;

/**
 * 账户表数据访问层接口实现
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 2:04 下午
 */
public class AccountDaoImpl implements AccountDao {

    @Override
    public void save() {
        System.out.println("保存账户数据");
    }

}

CGLibProxy代理工厂类

package com.github.xuchengen.proxy.statics;

import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;

import java.lang.reflect.Method;

/**
 * CGLib代理工厂类
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 4:05 下午
 */
public class CGlibProxyFactory implements MethodInterceptor {

    private Object target;

    public CGlibProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * 为目标对象生成代理对象
     */
    public Object getProxyInstance() {
        //工具类
        Enhancer en = new Enhancer();
        //设置父类
        en.setSuperclass(target.getClass());
        //设置回调函数
        en.setCallback(this);
        //创建子类对象代理
        return en.create();
    }

    @Override
    public Object intercept(Object o, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
        try {
            System.out.println("开启事务");
            Object returnValue = method.invoke(target, args);
            System.out.println("关闭事务");
        } catch (Exception e) {
            System.out.println("事务回滚");
        }
        return null;
    }

}

CGLibDynamicProxyTest测试类

package com.github.xuchengen.proxy.statics;

/**
 * JDK动态代理测试
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 3:39 下午
 */
public class CGLibDynamicProxyTest {

    public static void main(String[] args) {
        AccountDao accountDao = new AccountDaoImpl();

        CGlibProxyFactory cGlibProxyFactory = new CGlibProxyFactory(accountDao);

        AccountDao proxyInstance = (AccountDao) cGlibProxyFactory.getProxyInstance();

        proxyInstance.save();
    }

}

控制台输出

开启事务
保存账户数据
关闭事务

Java设计模式之动态代理JDK版

代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

简言之,代理模式就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式。

代理模式UML类图

动态代理JDK版

动态代理利用了JDK标准库API,动态地在内存中构建代理对象,从而实现对目标对象的代理功能。动态代理又被称为JDK代理或接口代理。

静态代理与动态代理的区别主要在:

1、静态代理在编译时就已经实现,编译完成后代理类是一个实际的class文件

2、动态代理是在运行时动态生成的,即编译完成后没有实际的class文件,而是在运行时动态生成类字节码,并加载到JVM中

特点:
动态代理对象不需要实现接口,但是要求目标对象必须实现接口,否则不能使用动态代理。

JDK中生成代理对象主要涉及的类

java.lang.reflect.Proxy

/**
 * 创建代理实例
 *
 * @param loader            目标对象类加载器
 * @param interfaces        目标对象实现的接口类
 * @param invocationHandler 事件处理器
 * @return 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序
 */
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler invocationHandler);

java.lang.reflect.InvocationHandler

/**
 * 代理实例上处理方法调用并返回结果
 *
 * @param proxy  代理对象
 * @param method 方法
 * @param args   方法参数
 * @return Object
 * @throws Throwable 异常
 */
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable;

动态代理JDK版代码示例

AccountDao接口类

package com.github.xuchengen.proxy.statics;

/**
 * 账户表数据访问层接口
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 2:03 下午
 */
public interface AccountDao {

    /**
     * 保存
     */
    void save();

}

AccountDaoImpl接口实现类

package com.github.xuchengen.proxy.statics;

/**
 * 账户表数据访问层接口实现
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 2:04 下午
 */
public class AccountDaoImpl implements AccountDao {

    @Override
    public void save() {
        System.out.println("保存账户数据");
    }

}

ProxyFactory代理工厂类

package com.github.xuchengen.proxy.statics;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;

/**
 * 代理工厂类
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 3:33 下午
 */
public class ProxyFactory {

    private Object target;

    public ProxyFactory(Object target) {
        this.target = target;
    }

    /**
     * 为目标对象生成代理对象
     *
     * @param invocationHandler 事件处理器
     * @return Object
     */
    public Object getProxyInstance(InvocationHandler invocationHandler) {
        return Proxy.newProxyInstance(target.getClass().getClassLoader(),
                target.getClass().getInterfaces(),
                invocationHandler);
    }
}

JDKDynamicProxyTest测试类

package com.github.xuchengen.proxy.statics;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;

/**
 * JDK动态代理测试
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 3:39 下午
 */
public class JDKDynamicProxyTest {

    public static void main(String[] args) {
        AccountDao accountDao = new AccountDaoImpl();

        ProxyFactory proxyFactory = new ProxyFactory(accountDao);

        AccountDao proxyInstance = (AccountDao) proxyFactory.getProxyInstance(new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {

                try {
                    System.out.println("开启事务");

                    method.invoke(accountDao, args);

                    System.out.println("提交事务");
                } catch (Exception e) {
                    System.out.println("事务回滚");
                }

                return null;
            }
        });

        proxyInstance.save();
    }

}

控制台输出

开启事务
保存账户数据
提交事务

Java设计模式之静态代理模式

代理模式是一种设计模式,提供了对目标对象额外的访问方式,即通过代理对象访问目标对象,这样可以在不修改原目标对象的前提下,提供额外的功能操作,扩展目标对象的功能。

简言之,代理模式就是设置一个中间代理来控制访问原目标对象,以达到增强原对象的功能和简化访问方式。

代理模式UML类图

静态代理

静态代理需要代理对象和目标对象实现一样的接口。

优点:

1、可以在不修改目标对象的前提下扩展目标对象的功能。

缺点:

1、冗余。由于代理对象要实现与目标对象一致的接口,会产生过多的代理类。

2、不易维护。一旦接口增加方法,目标对象与代理对象都要进行修改。

静态代理示例代码

AccountDao接口类

package com.github.xuchengen.proxy.statics;

/**
 * 账户表数据访问层接口
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 2:03 下午
 */
public interface AccountDao {

    /**
     * 保存
     */
    void save();

}

AccountDaoImpl接口实现类

package com.github.xuchengen.proxy.statics;

/**
 * 账户表数据访问层接口实现
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 2:04 下午
 */
public class AccountDaoImpl implements AccountDao {

    @Override
    public void save() {
        System.out.println("保存账户数据");
    }

}

AccountDaoProxy代理类

package com.github.xuchengen.proxy.statics;

/**
 * 账户表数据访问层代理
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 2:07 下午
 */
public class AccountDaoProxy implements AccountDao {

    private AccountDao accountDao;

    /**
     * 构造方法
     *
     * @param accountDao 账户表数据访问层接口
     */
    public AccountDaoProxy(AccountDao accountDao) {
        this.accountDao = accountDao;
    }

    @Override
    public void save() {
        try {
            System.out.println("开启事务");
            accountDao.save();
            System.out.println("提交事务");
        } catch (Exception e) {
            System.out.println("事务回滚");
        }
    }
}

StaticProxyTest测试类

package com.github.xuchengen.proxy.statics;

/**
 * 静态代理测试
 * 作者:徐承恩
 * 邮箱:xuchengen@gmail.com
 * 日期:2020/4/1 2:11 下午
 */
public class StaticProxyTest {

    public static void main(String[] args) {

        AccountDao accountDao = new AccountDaoImpl();

        AccountDaoProxy accountDaoProxy = new AccountDaoProxy(accountDao);

        accountDaoProxy.save();

    }

}

控制台输出

开启事务
保存账户数据
提交事务