核心(Core)
YMP 框架主要是由核心(Core)和模块(Module)组成,核心也称之为应用容器(IApplication),主要负责框架初始化、事件(Events)广播与监听、模块的定义及其生命周期管理、国际化资源管理(I18N)和类对象管理等,其核心功能是对包和类的自动扫描(AutoScan)、对象的生命周期管理、以及反转控制(IoC)、依赖注入(DI)和方法拦截(AOP)等。
Maven包依赖
<dependency>
<groupId>net.ymate.platform</groupId>
<artifactId>ymate-platform-core</artifactId>
<version>2.1.3</version>
</dependency>
框架初始化
YMP 框架的初始化方式有两种,一种是配置文件方式,另一种则是基于注解。我们更推荐两者配合使用,当两者共存时,配置文件方式更优先于注解方式(即,当注解和配置文件中对相同配置项赋值时,则优先使用配置文件中的非空值)。
基于配置文件初始化
YMP 框架默认使用名称为 ymp-conf.properties 的配置文件 ,默认该文件放置在 classpath 的根路径下,也可以通过 JVM 启动参数 -Dymp.configFile 指定具体配置文件路径。
具体加载流程如下:
- 首先,检查JVM启动参数
-Dymp.env判断当前系统远行环境(默认值:dev):-Dymp.env=test:测试环境,将优先加载ymp-conf_TEST.properties-Dymp.env=dev:开发环境,将优先加载ymp-conf_DEV.properties-Dymp.env=product:生产环境,将优先加载ymp-conf_PRODUCT.properties
- 若以上配置文件未找到,则尝试加载与当前操作系统类型相匹配的配置文件:
- Unix/Linux环境下,优先加载
ymp-conf_UNIX.properties - Windows环境下,优先加载
ymp-conf_WIN.properties
- Unix/Linux环境下,优先加载
- 若以上配置文件未找到,则尝试加载
ymp-conf.properties默认配置文件。
示例代码:
public class Starter {
private static final Log LOG = LogFactory.getLog(Starter.class);
public static void main(String[] args) throws Exception {
try (IApplication application = YMP.run(args)) {
if (application.isInitialized()) {
LOG.info("Everything depends on ability! -- YMP :)");
}
}
}
}
上述代码中通 过 YMP.run() 方法构建了一个 IApplication 接口实例对象,而这个 IApplication 对象就是框架应用容器。
基于注解初始化
YMP 框架从 2.1.0 版本开始支持通过注解针对各个模块进行初始化配置,项目中允许包括多个基于注解的配置类,并支持通过 JVM 启动参数 -Dymp.mainClass 任意切换使其生效,方便根据自身业务特点灵活调配。
示例代码:
@EnableAutoScan
@EnableBeanProxy
@EnableDevMode
@DefaultPasswordProcessClass
@EventsConf(mode = Events.MODE.NORMAL, threadPoolSize = 200)
@I18nConf(defaultLocale = "zh_CN")
@LogConf(allowConsoleOutput = true, configFile = "${user.dir}/cfgs/log4j.xml")
@ConfigurationConf(configHome = "${user.dir}/configs", checkTimeInterval = 300000)
public class Starter {
static {
System.setProperty(IApplication.SYSTEM_MAIN_CLASS, Starter.class.getName());
}
private static final Log LOG = LogFactory.getLog(Starter.class);
public static void main(String[] args) throws Exception {
try (IApplication application = YMP.run(args)) {
if (application.isInitialized()) {
LOG.info("Everything depends on ability! -- YMP :)");
}
}
}
}
应用容器扩展初始化处理器接口(IApplicationInitializer)
为了让开发者可以对应用容器有更多的可定制、扩展能力,框架提供了应用容器扩展初始化处理器(IApplicationInitializer) 接口,其通过SPI方式在框架启动时自动扫描类和包路径下 META-INF/services/或 META-INF/services/internal/ 目录中所有 名称为 net.ymate.platform.core.IApplicationInitializer 的文件并加载文件中指定的所有接口实现类。
该接口可以帮助你完成如下操作:
| 方法名称 | 描述 |
|---|---|
| afterEventInit | 当事件管理器初始化完毕后将调用此方法 |
| beforeBeanLoad | 当对象加载器开始执行加载动作前将调用此方法 |
| beforeModuleManagerInit | 当模块管理器执行初始化动作前将调用此方法 |
| beforeBeanFactoryInit | 当对象工厂执行初始化动作前将调用此方法 |
自定义Banner
以 Maven 工程为例,在 src/main/resources 路径下新建名称为 banner.txt 的文本文件,该文件编译后将被放置在 classes 目录下,框架在启动时会优先加载该文件内容,若文件不存在或文件内容为空时,将默认输出如下内容:
__ __ __ ___ ___
\ \/ // |/ // _ \
\ // /|_/ // ___/
/_//_/ /_//_/ www.ymate.net
基本配置
YMP框架从 2.1.0 版本开始遵循零配置原则,在不提供配置文件的情况下,尽可能使用默认配置以保证各个模块能够正确初始化。
配置文件参数说明
#-------------------------------------
# 框架基本配置参数
#-------------------------------------
# 是否为开发模式, 默认值: false
ymp.dev_mode=
# 框架自动扫描的包名称集合, 多个包名之间用'|'分隔, 默认已包含net.ymate.platform包, 其子包也将被扫描
ymp.packages=
# 排除包名称集合, 多个包名之间用'|'分隔, 被包含在包路径下的类文件在扫描过程中将被忽略
ymp.excluded_packages=
# 排除包文件名称集合, 多个文件名称之间用'|'分隔, 被包含的JAR或ZIP文件在扫描过程中将被忽略
ymp.excluded_files=
# 排除模块类名集合, 多个模块类名之间用'|'分隔, 被包含的模块在加载过程中将被忽略
ymp.excluded_modules=
# 包含模块名集合, 多个模块类名之间用'|'分隔,若设置该参数则框架初始化时仅加载被包含的模块
ymp.included_modules=
# 国际化资源默认语言设置, 默认采用系统环境语言
ymp.default_locale=zh_CN
# 国际化资源事件监听处理器, 默认值: 空
ymp.i18n_event_handler_class=
# 默认密码处理器, 默认值: 空
ymp.default_password_process_class=
# 自定义扩展参数, xxx表示自定义参数名称, vvv表示参数值
ymp.params.xxx=vvv
#-------------------------------------
# 框架事件初始化参数
#-------------------------------------
# 默认事件触发模式, 取值范围: NORMAL-同步执行, ASYNC-异步执行, 默认值: ASYNC
ymp.configs.event.default_mode=
# 事件管理提供者接口实现, 默认值: net.ymate.platform.core.event.impl.DefaultEventProvider
ymp.configs.event.provider_class=
# 初始化线程池大小, 默认值: Runtime.getRuntime().availableProcessors()
ymp.configs.event.thread_pool_size=
# 最大线程池大小, 默认值: 200
ymp.configs.event.thread_max_pool_size=
# 线程队列大小, 默认值: 1024
ymp.configs.event.thread_queue_size=
针对配置文件,YMP框架从 2.1.2 版本开始支持将任意参数项加密处理,示例如下:
ymp.params.xxx=ENC(X4+Fm5GYxsWqGS6d2vLHh11G/R7yaUoDWo4lMH9IShb2C7jx+rlViw==)
- 通过
JVM参数-Dymp.passPrefix自定义前缀(区分大小写),默认为:ENC。 - 通过
JVM参数-Dymp.passClass自定义密码处理器接口实现类,默认为:DefaultPasswordProcessor。 - 当使用默认密码处理器时,可以通过
JVM参数-Dymp.passKey自定义加/解密密钥。
配置注解参数说明
以下所列注解仅用于 YMP 框架基本配置,关于其它模块所提供的注解和配置项说明,请参见各模块文档。
@EnableAutoScan
用于开启包和类的自动扫描特性,默认情况下框架在启动时不会进行自动扫描。
| 配置项 | 描述 |
|---|---|
| value | 自动扫描的包名称集合,默认已包含主程序类所在包。 |
| excluded | 排除包名称集合, 被包含在包路径下的类文件在扫描过程中将被忽略。 |
| excludedFiles | 排除包文件名称集合, 被包含的JAR或ZIP文件在扫描过程中将被忽略。 |
| excludedModules | 排除模块类名集合, 被包含的模块在加载过程中将被忽略。 |
| includedModules | 包含模块类名集合,若设置该参数则框架初始化时仅加载被包含的模块 |
| factoryClass | 对象加载器工厂类型,默认值:DefaultBeanLoadFactory |
示例:
@EnableAutoScan(
value = {"net.ymate.module", "com.myproject.demo"},
excluded = "net.ymate.module.captcha",
factoryClass = DemoBeanLoadFactory.class)
@EnableBeanProxy
用于开启代理并配置代理工厂类型,框架提供了三种代理工厂接口实现类:
DefaultProxyFactory.class:基于CGLIB实现的默认代理工厂。JavassistProxyFactory:基于Javassist实现的代理工厂。NoOpProxyFactory:空操作代理工厂,使用它表示需要禁用框架的AOP特性。
| 配置项 | 描述 |
|---|---|
| factoryClass | 代理工厂类型,默认值:DefaultProxyFactory |
示例:
@EnableBeanProxy(factoryClass = JavassistProxyFactory.class)
@EnableDevMode
开启开发模式,无参数,与 ymp.dev_mode=true 作用相同,优先级低于 JVM 启动参数 -Dymp.env。
@EventConf
框架事件初始化参数。
| 配置项 | 描述 |
|---|---|
| mode | 取值范围: NORMAL-同步执行, ASYNC-异步执行, 默认值: ASYNC |
| providerClass | 事件管理提供者接口实现,默认值:DefaultEventProvider |
| threadPoolSize | 初始化线程池大小,默认值:Runtime.getRuntime().availableProcessors() |
| threadMaxPoolSize | 最大线程池大小,默认值:200 |
| threadQueueSize | 线程队列大小,默认值:1024 |
示例:
@EventsConf(mode = Events.MODE.NORMAL,
threadPoolSize = 10,
threadMaxPoolSize = 200,
threadQueueSize = 1000)
@I18nConf
国际化初始化参数。
| 配置项 | 描述 |
|---|---|
| defaultLocale | 国际化资源默认语言设置, 默认采用系统环境语言。 |
| eventHandlerClass | 国际化资源事件监听处理器。 |
示例:
@I18nConf(defaultLocale = "zh_CN", eventHandlerClass = I18nWebEventHandler.class)
@DefaultPaswordProcessClass
设置框架默认密码处理器,与 ymp.default_password_process_class作用相同。
| 配置项 | 描述 |
|---|---|
| value | 默认密码处理器类型,默认值:DefaultPasswordProcessor |
示例:
@DefaultPasswordProcessClass(DemoPasswordProcessor.class)
@Params
@Param
自定义扩展参数,与 ymp.params.xxx=vvv作用相同。
| 配置项 | 描述 |
|---|---|
| name | 参数名称 |
| value | 值 |
示例:
@Params({@Param(name = "xxx", value = "vvv")})
@ParamValue
自定义扩展参数值注入。
| 配置项 | 描述 |
|---|---|
| value | 自定义扩展参数名称, 若未提供则使用成员变量或方法参数名称 |
| defaultValue | 自定义扩展参数默认值 |
| replaceEnvVariable | 是否替换字符串中的环境变量 |
示例:
@ParamValue(value = "xxx", defaultValue = "${root}/a", replaceEnvVariable = true)
关于SPI加载机制
YMP 框架从 2.1.0 版本开始大量采用SPI的加载机制,允许开发者针对框架中诸多功能特性进行自定义,如新版框架中的模块就已经放弃了自动扫描,转而采用了 SPI 机制进行加载,更多的细节请注意各文档中的相关描述。
YMP 框架提供了两种 SPI 配置文件存放路径:
META-INF/services/internal/:内部配置路径用于存放默认配置,是否使用默认配置由功能特性的设计者决定。META-INF/services/:自定义配置路径,该路径将优先于内部配置路径被加载。
在以上配置文件路径中存放的配置文件为普通文本文件,无扩展名且名称一般为接口类文件全称。
示例一:加载指定业务接口实例
步骤1: 定义 IDemoService 服务接口及两个实现类。
package net.ymate.demo.service;
/**
* 示例服务接口类
*/
public interface IDemoService {
/**
* 执行业务逻辑
*
* @return 返回执行结果
*/
String doService();
}
package net.ymate.demo.service.impl;
/**
* 示例服务接口实现类:DemoOneService
*/
public class DemoOneServiceImpl implements IDemoService{
@Override
public String doService() {
return "来自 DemoOneService 的接口实现。";
}
}
package net.ymate.demo.service.impl;
/**
* 示例服务接口实现类:DemoTwoService
*/
public class DemoTwoServiceImpl implements IDemoService{
@Override
public String doService() {
return "来自 DemoTwoService 的接口实现。";
}
}
步骤2: 在内部配置路径 META-INF/services/internal/ 中添加 SPI 配置文件,内容如下:
# more META-INF/services/internal/net.ymate.demo.service.IDemoService
net.ymate.demo.service.impl.DemoOneServiceImpl
步骤3: 加载并执行业务逻辑。
public class Demo {
public static void main(String[] args) throws Exception {
IDemoService demoService = ClassUtils.getExtensionLoader(IDemoService.class).getExtension();
if (demoService != null) {
// 此处执行输出结果为:来自 DemoOneService 的接口实现。
System.out.println(demoService.doService());
}
}
}
步骤4: 在自定义配置路径 META-INF/services/ 中添加 SPI 配置文件,内容如下:
# more META-INF/services/net.ymate.demo.service.IDemoService
net.ymate.demo.service.impl.DemoTwoServiceImpl
步骤5: 再次加载并执行业务逻辑。
public class Demo {
public static void main(String[] args) throws Exception {
IDemoService demoService = ClassUtils.getExtensionLoader(IDemoService.class).getExtension();
if (demoService != null) {
// 此处执行输出结果为:来自 DemoTwoService 的接口实现。
System.out.println(demoService.doService());
}
}
}
通过本例可以清楚的知道,当通过 ClassUtils.getExtensionLoader 方法加载指定接口类的 SPI 配置时,其首先尝试加载自定义配置路径下的配置文件,若配置文件存在则加载并返回,否则尝试从内部配置路径中加载。
示例二:加载指定业务接口多实例
根据 示例一 的配置,通过以下示例展示如何获取业务接口所配置的全部实现类及实现类实例对象:
public class Demo {
public static void main(String[] args) throws Exception {
// 获取指定业务接口配置的所有实现类类型
List<Class<IDemoService>> demoServiceClasses = ClassUtils.getExtensionLoader(IDemoService.class, true).getExtensionClasses();
if (demoServiceClasses != null) {
demoServiceClasses.forEach(demoServiceClass -> System.out.println(demoServiceClass.getName()));
}
// 获取指定业务接口配置的所有实现类实例对象
List<IDemoService> demoServiceImpls = ClassUtils.getExtensionLoader(IDemoService.class, true).getExtensions();
if (demoServiceImpls != null) {
demoServiceImpls.forEach(demoServiceImpl -> System.out.println(demoServiceImpl.doService()));
}
}
}
本例中通过 ClassUtils.getExtensionLoader 方法的第二个参数 alwaysInternal 是用来指定本次操作是否强制加载内部配置路径,所示需要开发人员自行根据实际业务情况合理使用。
自动扫描(AutoScan)
YMP 框架初始化时默认并未开启自动扫描,可以通过 @EnableAutoScan 注解或者通过在 pom.xml 中引入以下依赖包来开启:
<dependency>
<groupId>net.ymate.platform</groupId>
<artifactId>ymate-platform-starter</artifactId>
<version>2.1.3</version>
</dependency>
自动扫描程序将根据 @EnableAutoScan 注解或配置文件中 ymp.packages 的参数配置,遍历指定包路径下(含子包)所有被 @Bean 注解声明的类文件,分析其所实现的接口类型并向应用容器注册,使用时仅需告知应用容器你需要的实例类型或接口类型即可得到对应的实例对象。
若不希望某个类被自动扫描,只需在该类上声明 @Ignored 注解,自动扫描程序将会忽略它的存在。
相同接口的多个实现类被同时注册到应用容器时,通过接口类型获取的实例对象将是最后被注册到容器的那一个,此时只能通过实例对象类型才能正确获取。
示例一:基本操作
// 业务接口
public interface IDemo {
String sayHi();
}
// 业务接口实现类:单例模式
@Bean
public class SingletonDemoBean implements IDemo {
@Override
public String sayHi() {
return "Hello, YMP!";
}
}
// 业务接口实现类:非单例模式
@Bean(singleton = false)
public class DemoBean implements IDemo {
@Override
public String sayHi() {
return "Hello, YMP!";
}
}
@EnableAutoScan
public class Starter {
static {
System.setProperty(IApplication.SYSTEM_MAIN_CLASS, Starter.class.getName());
}
private static final Log LOG = LogFactory.getLog(Starter.class);
public static void main(String[] args) throws Exception {
try (IApplication application = YMP.run(args)) {
// 1. 通过接口获取实例对象
IDemo demo = application.getBeanFactory().getBean(IDemo.class);
LOG.info(demo.sayHi());
// 2. 直接获取实例对象
demo = application.getBeanFactory().getBean(DemoBean.class);
LOG.info(demo.sayHi());
}
}
}
示例二:自定义对象处理器
public class DemoBeanHandler implements IBeanHandler {
@Override
public Object handle(Class<?> targetClass) throws Exception {
// 自定义对象处理逻辑...
return BeanMeta.create(targetClass, true);
}
}
// 自定义对象处理器 (将取代原来的处理器)
@Bean(handler=DemoBeanHandler.class)
public class DemoBean implements IDemo {
@Override
public String sayHi() {
return "Hello, YMP!";
}
}
示例三:自定义初始化后处理逻辑
@Bean
public class DemoBean implements IDemo, IBeanInitializer {
@Override
public String sayHi() {
return "Hello, YMP!";
}
@Override
public void afterInitialized(IBeanFactory beanFactory) throws Exception {
System.out.println(sayHi() + " ---- afterInitialized.");
}
}
依赖注入(DI)
通过在类成员上声明 @Inject 和 @By 注解来完成依赖注入的设置,且只有被应用容器管理的类对象才支持依赖注入,下面举例说明:
示例一:基本操作
// 业务接口
public interface IDemo {
String sayHi();
}
// 业务接口实现类1
@Bean
public class DemoOne implements IDemo {
@Override
public String sayHi() {
return "Hello! I'm DemoOne.";
}
}
// 业务接口实现类2
@Bean
public class DemoTwo implements IDemo {
@Override
public String sayHi() {
return "Hello! I'm DemoTwo.";
}
}
@Bean
public class TestDemo {
private static final Log LOG = LogFactory.getLog(TestDemo.class);
@Inject
private IDemo demo1;
@Inject
@By(DemoOne.class)
private IDemo demo2;
public void sayHi() {
// demo1注入的是最后被注册到容器的IDemo接口实现
LOG.info(demo1.sayHi());
// demo2注入的是由@By注解指定的DemoOne类
LOG.info(demo2.sayHi());
}
}
@EnableAutoScan
public class Starter {
static {
System.setProperty(IApplication.SYSTEM_MAIN_CLASS, Starter.class.getName());
}
public static void main(String[] args) throws Exception {
try (IApplication application = YMP.run(args)) {
application.getBeanFactory().getBean(TestDemo.class).sayHi();
}
}
}
示例二:自定义注入注解
可以通过 @Injector 注解声明一个 IBeanInjector 接口实现类来向框架注册自定义的注入处理逻辑,下面举例说明如何实现一个名为 @DemoInject 的自定义注入注解:
- 当使用自定义注解进行依赖注入操作时可以忽略
@Inject注解,若存在则优先执行@Inject注入并将此对象当作IBeanInjector接口方法参数传入。 - 当成员变量被声明多个自定义注入注解规则时(不推荐),根据框架加载顺序,仅执行首个注入规则。
// 定义一个业务接口
public interface IInjectBean {
String getName();
void setName(String name);
}
// 业务接口实现类
@Bean
public class InjectBeanImpl implements IInjectBean {
private String name;
@Override
public String getName() {
return name;
}
@Override
public void setName(String name) {
this.name = name;
}
}
// 业务对象包装器类
public class InjectBeanWrapper implements IInjectBean {
private final IInjectBean targetBean;
public InjectBeanWrapper(IInjectBean targetBean) {
this.targetBean = targetBean;
}
@Override
public String getName() {
return targetBean.getName();
}
@Override
public void setName(String name) {
targetBean.setName(name);
}
}
// 自定义一个注入注解
@Target({ElementType.FIELD})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface DemoInject {
String value();
}
// 为自定义注入注解编写注入逻辑
@Injector(DemoInject.class)
public class DemoBeanInjector implements IBeanInjector {
@Override
public Object inject(IBeanFactory beanFactory, Annotation annotation, Class<?> targetClass, Field field, Object originInject) {
// 为从自定义注解取值做准备
DemoInject anno = (DemoInject) annotation;
if (originInject == null) {
// 若通过@Inject注入的对象不为空则为其赋值
IInjectBean bean = new InjectBeanImpl();
bean.setName(anno.value());
// 创建包装器
originInject = new InjectBeanWrapper(bean);
} else {
// 直接创建包装器并赋值
InjectBeanWrapper wrapper = new InjectBeanWrapper((IInjectBean) originInject);
wrapper.setName(anno.value());
//
originInject = wrapper;
}
return originInject;
}
}
@Bean
public class TestApp {
@Inject
@DemoInject("demo")
private IInjectBean bean;
public IInjectBean getBean() {
return bean;
}
}
@EnableAutoScan
public class Starter {
static {
System.setProperty(IApplication.SYSTEM_MAIN_CLASS, Starter.class.getName());
}
private static final Log LOG = LogFactory.getLog(Starter.class);
public static void main(String[] args) throws Exception {
try (IApplication application = YMP.run(args)) {
TestApp testApp = application.getBeanFactory().getBean(TestApp.class);
IInjectBean bean = testApp.getBean();
LOG.info(bean.getName());
}
}
}
拦截器(AOP)
YMP 框架的 AOP 是基于代理(Proxy)技术实现的方法拦截,按其执行方向分为前置拦截和后置拦截,框架初始化时默认并未开启代理,可以通过 @EnableBeanProxy 注解或者通过在 pom.xml 中引入以下依赖包来开启:
<dependency>
<groupId>net.ymate.platform</groupId>
<artifactId>ymate-platform-starter</artifactId>
<version>2.1.3</version>
</dependency>
拦截器可以通过以下注解进行配置:
-
@Before:用于设置一个类或方法的前置拦截器,声明在类上的前置拦截器将被应用到该类所有方法上。
-
@After:用于设置一个类或方法的后置拦截器,声明在类上的后置拦截器将被应用到该类所有方法上。
-
@Around:用于同时配置一个类或方法的前置和后置拦截器。
-
@Clean:用于清理类上全部或指定的拦截器,被清理的拦截器将不会被执行。
-
@ContextParam:用于设置上下文参数,主要用于向拦截器传递参数配置。
-
@Ignored:声明一个方法将忽略一切拦截器配置。
- 声明
@Ignored注解的方法、非公有方法和 Object 类方法及 Object 类重载方法将不被拦截器处理。 - 使用
@Interceptor注解声明的拦截器类,框架将自动将其注册到应用容器中并支持依赖注入等特性。
自定义拦截器
编写拦截器可以通过实现 IInterceptor 接口或直接继承 AbstractInterceptor 抽象类来完成,一个类方法可以设置多个拦截器,并按照设置的先后顺序执行。拦截器接口方法返回值为非 null 对象时,表示方法 已被拦截,将停止执行其它拦截器并使用当前拦截器接口方法的返回值作为被拦截方法的执行结果立即返回。
可以通过 @ContextParam 注解配置拦截器上下文参数,@ContextParam注解的 value 属性允许通过 $xxx 的格式支持从框架全局参数中获取 xxx 的值。
示例一: 通过接口创建自定义拦截器
@Interceptor
public class DemoInterceptor implements IInterceptor {
@Override
public Object intercept(InterceptContext context) throws Exception {
// 判断当前拦截器执行方向
switch (context.getDirection()) {
// 前置
case BEFORE:
System.out.println("Before intercept...");
// 获取拦截器上下文参数
String param = context.getContextParams().get("param");
if (StringUtils.isNotBlank(param)) {
// 若参数值不为空则替换被拦截方法的返回值
return param;
}
break;
// 后置
case AFTER:
System.out.println("After intercept...");
}
return null;
}
}
示例二: 通过继承抽象类创建自定义拦截器
@Interceptor
public class DemoInterceptor extends AbstractInterceptor {
@Override
protected Object before(InterceptContext context) throws InterceptException {
System.out.println("Before intercept...");
// 获取拦截器上下文参数
String param = context.getContextParams().get("param");
if (StringUtils.isNotBlank(param)) {
// 若参数值不为空则替换被拦截方法的返回值
return param;
}
return null;
}
@Override
protected Object after(InterceptContext context) throws InterceptException {
System.out.println("After intercept...");
return null;
}
}
示例三: 在方法上使用拦截器
@Bean
public class TestApp {
@Before(DemoInterceptor.class)
public String beforeTest() {
return "前置拦截测试";
}
@After(DemoInterceptor.class)
public String afterTest() {
return "后置拦截测试";
}
@Around(DemoInterceptor.class)
@ContextParam(key = "param", value = "helloworld")
public String allTest() {
return "拦截器参数传递";
}
}
@EnableAutoScan
@EnableBeanProxy
public class Starter {
static {
System.setProperty(IApplication.SYSTEM_MAIN_CLASS, Starter.class.getName());
}
private static final Log LOG = LogFactory.getLog(Starter.class);
public static void main(String[] args) throws Exception {
try (IApplication application = YMP.run(args)) {
TestApp testApp = application.getBeanFactory().getBean(TestApp.class);
LOG.info(testApp.beforeTest());
LOG.info(testApp.afterTest());
LOG.info(testApp.allTest());
}
}
}
示例四: 在类上使用拦截器
@Bean
@Before(DemoInterceptor.class)
@ContextParams({@ContextParam(key = "param", value = "helloworld"))})
public class TestApp {
public String beforeTest() {
return "前置拦截测试";
}
@After(DemoInterceptor.class)
public String afterTest() {
return "后置拦截测试";
}
@Clean
public String cleanTest() {
return "清理拦截器测试";
}
}
@EnableAutoScan
@EnableBeanProxy
public class Starter {
static {
System.setProperty(IApplication.SYSTEM_MAIN_CLASS, Starter.class.getName());
}
private static final Log LOG = LogFactory.getLog(Starter.class);
public static void main(String[] args) throws Exception {
try (IApplication application = YMP.run(args)) {
TestApp testApp = application.getBeanFactory().getBean(TestApp.class);
LOG.info(testApp.beforeTest());
LOG.info(testApp.afterTest());
LOG.info(testApp.cleanTest());
}
}
}