前言:
有时我们需要封装功能类库供第三方使用,这时候打包和我们平时发布项目有所不同。假设我们现在要对外提供一个计算功能,使用者只需要传入计算参数就能实现结果异步返回。最后还得对jar包进行混淆
1.编写回调函数类
我们先抽像出回调函数接口:
再新建一计算器类,含有加法和乘法:
一年级学生算加法:
二年级学生算乘法:
调用结果:
一般回调都是异步,比如说一年级学生在调用加法后要吃棒棒糖,二年级学生调用后要吃冰淇淋,而计算需要时间,不能让祖国的花朵在那傻等不是。
最终代码如下:
回调接口
/**
* 回调接口--在不确定使用者的情况下,建立一使用标准,实现该标准的都能使用此标准的回调函数
*/
public interface Norm {
/**
* 回调函数,接收反馈--通俗点来讲,就是你委托某人帮你办事(此例是委托计算器进行计算),他办完后通知你的渠道。
* 此回调函数的r参数就是被委托人完事后(你调用的函数结束)返回的处理结果
*/
void feedBack(int r);
}
计算器类
/**
* 计算器类
*/
public class Calculator {
/**
* 加法计算
* @param a 参数一
* @param b 参数二
* @param norm 使用者
*/
public void add(int a, int b, Norm norm) throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"加法需要3秒");
Thread.sleep(3000);
System.out.println(Thread.currentThread().getName()+"加法完成,通知委托人");
norm.feedBack(a+b);
}
/**
* 乘法计算
* @param a 参数一
* @param b 参数二
* @param norm 使用者
*/
public void sub(int a, int b, Norm norm) throws InterruptedException {
System.out.println(Thread.currentThread().getName()+"乘法需要4秒");
Thread.sleep(4000);
System.out.println(Thread.currentThread().getName()+"乘法完成,通知委托人");
norm.feedBack(a*b);
}
public static void main(String[] args) throws InterruptedException {
First first = new First();
first.add(9,8);
Second second = new Second();
second.sub(9,8);
}
一年级学生
/**
* 一年级学生
*/
public class First implements Norm{
@Override
public void feedBack(int r) {
System.out.println(Thread.currentThread().getName()+"一年级学生通过回调函数获取计算结果:"+r);
}
public void add(int a,int b) {
System.out.println(Thread.currentThread().getName()+"一年级使用计算器算加法:"+a+"+"+b+"=");
new Thread(()->{
try {
Thread.currentThread().setName("一年级子线程");
new Calculator().add(a,b,this);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
).start();
System.out.println(Thread.currentThread().getName()+"一年级学生吃棒棒糖");
}
}
二年级学生
/**
* 二年级学生
*/
public class Second implements Norm{
@Override
public void feedBack(int r) {
System.out.println(Thread.currentThread().getName()+"二年级学生通过回调函数获取计算结果:"+r);
}
public void sub(int a,int b){
System.out.println(Thread.currentThread().getName()+"二年级使用计算器算乘法:"+a+"*"+b+"=");
new Thread(()->{
try {
Thread.currentThread().setName("二年级子线程");
new Calculator().sub(a,b,this);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
).start();
System.out.println(Thread.currentThread().getName()+"二年级学生吃冰淇淋");
}
}
2.直接打JAR包(使用者必须手动)
3.加上组件扫描后打包
打包过程不再赘述
组件已注册,使用的时候只要扫描工具包所在包路径即可
包扫描可以去掉,同一路径默认会扫描
更改工具包的包路径
4.提供自定义注解
定义配置类,做为组件入口:
/**
* 组件入口配置类,用来扫描所有组件
*/
@Configuration
@ComponentScan("com.stu.uitilsjar.**")
public class UtilsConfig {
}
定义一个注解,用来导入配置类
@Retention(RetentionPolicy.RUNTIME)
@Target({
ElementType.TYPE})
@Documented
@Import({
UtilsConfig.class}) //此处是关键,导入组件入口配置类--使用者如果使用此注解,则导入配置类,配置类则扫描工具包下组件
public @interface EnableUtilsConfig {
}
现在我们换种打包方式,就像平常打包项目Jar包一样
生成的包如下
项目中再次重新导入jar包
5.使用spring.factories自动装配
重新打包后重新引入
6.混淆JAR包
根据情况配置插件
<build>
<finalName>${artifactId}</finalName>
<plugins>
<plugin>
<groupId>com.github.wvengen</groupId>
<artifactId>proguard-maven-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals><goal>proguard</goal></goals>
</execution>
</executions>
<configuration>
<proguardVersion>6.2.2</proguardVersion>
<injar>${project.build.finalName}.jar</injar>
<outjar>${project.build.finalName}.jar</outjar>
<!--<proguardInclude>${project.basedir}/proguard.cfg</proguardInclude>-->
<obfuscate>true</obfuscate>
<options>
<!-- 不做收缩(删除注释、未被引用代码)-->
<option>-dontshrink</option>
<!-- 不做优化(变更代码实现逻辑)-->
<option>-dontoptimize</option>
<!--保持目录结构,否则spring的自动注入无法使用-->
<option>-keepdirectories</option>
<option>-keepattributes Exceptions,InnerClasses,Signature,Deprecated,
SourceFile,LineNumberTable, *Annotation*,EnclosingMethod
</option>
<option>-adaptclassstrings</option>
<option>
<!-- 保护程序入口 -->
-keep class com.stu.uitilsjar.UitilsjarApplication { *; }
</option>
<option>-keepnames interface ** { *; }</option>
<!-- <!– 固定几个类不能混淆–>-->
<option>-keep class com.stu.uitilsjar.callback.First { *; }</option>
<option>-keep class com.stu.uitilsjar.callback.Second { *; }</option>
<!-- 此选项将在所有包的所有类中保存所有原始定义的注释.-->
<option>
-keep class * {
@org.springframework.beans.factory.annotation.Autowired *;
@org.springframework.beans.factory.annotation.Value *;
@org.springframework.stereotype.Service *;
@org.springframework.stereotype.Component *;
@org.springframework.scheduling.annotation.Scheduled *;
}
</option>
</options>
<libs>
<!-- Include main JAVA library required.-->
<lib>${java.home}/lib/rt.jar</lib>
<lib>${java.home}/lib/jce.jar</lib>
</libs>
</configuration>
<dependencies>
<dependency>
<groupId>net.sf.proguard</groupId>
<artifactId>proguard-base</artifactId>
<version>6.2.2</version>
</dependency>
</dependencies>
</plugin>
</plugins>
</build>