自定义的注解 ,可通过Spring快速的获取所有使用该注解的类或方法或属性,以及注解内的值。
自定义一个注解
@Target({ ElementType.TYPE, ElementType.METHOD }) //可以用在方法或者类上面
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Fooish {
String[] tags() default { "all" };
}
定义一个接口,以及两个实现类
public interface Foo{
void bar();
}
/** FooA **/
public class FooA implements Foo{
@Override
@Fooish(tags={"this_is_method"})
public void bar(){
System.out.println("I am number 6!");
}
}
/** FooB **/
@Fooish(tags= {"this_is_class"})
@Component // 一定得写,有这个注解,Spring才会将这个类实例化
public class FooB implements Foo{
@Override
public void bar(){
System.out.println("I am not a number, I am a free man!");
}
}
配置Spring
首先引入Spring的依赖包,
配置文件添加,通过注解实例化Bean
<mvc:annotation-driven />
或者<context:component-scan />
<!-- 让Spring扫描我们的自定义注解-->
<context:component-scan base-package="cn.itenlee">
<context:include-filter type="annotation" expression="cn.itenlee.annotation.Fooish" />
</context:component-scan>
测试
加上@Component
,当Spring启动并实例化该类的时候,会调用afterPropertiesSet
方法
@Component
public class MyFooishHandler implements ApplicationContextAware, InitializingBean {
private ApplicationContext applicationContext;
private List<String> allFooish = new ArrayList<>();
@Override
public void afterPropertiesSet() throws Exception {
scanFooishClass();
scanFooishMethod();
System.out.println(allFooish);
}
/**
* 查找 用 Fooish 注解的 类
* @throws Exception
*/
private void scanFooishClass() throws Exception {
final Map<String, Object> permissionMap = applicationContext.getBeansWithAnnotation(Fooish.class);
for (final Object permissionObject : permissionMap.values()) {
final Class<? extends Object> permissionClass = permissionObject.getClass();
final Fooish annotation = permissionClass.getAnnotation(Fooish.class);
if(annotation != null) {
allFooish.addAll(Arrays.asList(annotation.tags()));
}
}
}
/**
* 查找 用 Component 注解的 类 下面 用 Fooish 注解的方法
* @throws Exception
*/
private void scanFooishMethod() throws Exception{
final Map<String, Object> controllerMap = applicationContext.getBeansWithAnnotation(Component.class);
for (final Object controllerObject : controllerMap.values()) {
final Class<? extends Object> controllerClass = controllerObject.getClass();
for (Method method : controllerClass.getDeclaredMethods()) {
Fooish fooish = method.getAnnotation(Fooish.class);
if (fooish != null) {
allFooish.addAll(Arrays.asList(fooish.tags()));
}
}
}
}
@Override
public void setApplicationContext(final ApplicationContext applicationContext)
throws BeansException {
this.applicationContext = applicationContext;
}
}
通过AOP以该注解为切入点
Spring配置
<aop:aspectj-autoproxy proxy-target-class="true"/>
如果使用了SpringMVC,且想在Controller实现切入,则该配置需和SpringMVC配置在同一上下文中。
切面代码
@Aspect
@Component
public class PermissionAspect {
@Pointcut("@annotation(cn.itenlee.annotation.PermissionCode)")
public void permissionCodeAspect() {
}
@Before("permissionCodeAspect()")
public void doBefore(JoinPoint joinPoint) {
try {
//*========控制台输出=========*//
System.out.println("=====前置通知开始=====");
System.out.println("###请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
System.out.println("=====前置通知结束=====");
} catch (Exception e) {
//记录本地异常日志
e.printStackTrace();
}
}
@After("permissionCodeAspect()")
public void doAfterTask(JoinPoint joinPoint){
System.out.println("=====后置通知=====");
System.out.println("###请求方法:" + (joinPoint.getTarget().getClass().getName() + "." + joinPoint.getSignature().getName() + "()"));
System.out.println("=====后置通知end=====");
}
}
google 大法好,感谢来自国外的博主 http://techo-ecco.com/blog/spring-custom-annotations/