自定义注解实现A0P的权限控制
第一篇-自定义注解+A0P基本知识
1.注解概念
注解是一种能被添加到java代码中的元数据,类、方法、变量、参数和包都可以用注解来修饰。注解对于它所修饰的代码并没有直接的影响。
即:
注解是一种元数据形式。即注解是属于java的一种数据类型,和类、接口、数组、枚举类似。
注解用来修饰,类、方法、变量、参数、包。
注解不会对所修饰的代码产生直接的影响。
2 为什么要使用注解
在注解之前,XML被广泛用于元数据。但是随着项目中代码量的增大,XML维护变得越来越麻烦。开发人员希望元数据与代码是紧密耦合,而XML与代码之间的耦合非常松散。
1、假设您要设置一些应用程序范围内的常量。在这种情况下,XML是一个更好的选择,因为它与任何特定的代码段都不相关。
2、如果要将某个方法作为服务公开,则注解将是一个更好的选择,因为它需要与该方法紧密结合
现在,大多数框架都将XML和注解结合使用,以充分利用两者的积极方面。
3 注解的工作方式
注解仅仅是元数据,不包括任何业务逻辑。那它的使用者是谁呢?像@Override这种注解,JVM是它的使用者,它在字节码级别工作。如果我们自己编写了一个注解,那我们就要去实现它的消费者,否则,我们自定义的注解是没有任何作用的。
4 编写自定义注解
在编写自定义注解的时候,我们首先需要搞清楚几个默认的注解,这几个注解仅仅作用与另一个注解之上。
@Documented
注解表明这个注解要被javadoc记录。注解默认状态下是不被javadoc记录的。
@Retention
注解表明该注解保留到那个阶段,主要有三个值:
SOURCE —— 这种注解保留在源代码级别,编译时就会被忽略
CLASS —— 这种注解编译时被保留,在class文件中存在,但JVM将会忽略
RUNTIME —— 这种注解将被JVM保留,利用反射机制可以获取并使用。
@Target
t注解表明该注解作用的范围。包括package、method、field、构造方法、成员变量、枚举值等属性。
@Inherited
注解表明该注解是否影响子类。如果定义的注解上使用了@Inherited标记,则使用该注解的某个父类,它的子类默认继承所有的属性
5 案例需求
使用自定义注解+aop 完成dao层的拦截控制,比如我们要拦截删除和修改的方法,并把信息用日志的方式存到文件中
5.1环境搭建
创建Java项目,结构如下
5.2 创建自定义注解
@Target(ElementType.METHOD)//注解的作用目标是:方法
@Retention(RetentionPolicy.RUNTIME) //注解可以在运行时通过反射获取到
public @interface MyAnn {
String value() default "";
}
5.3创建切面类
package com.bobo.aop;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.springframework.stereotype.Component;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
@Aspect //标注为切面类
@Component //标注为ioc管理
public class MyAop {
//配置环绕通知,记录删除和修改的日志数据
//@annotation 固定写法
//com.bw.aop.MyAnn 自定义注解的全路径名
@Around(value = "@annotation(com.bw.aop.MyAnn)")
public void log1(ProceedingJoinPoint pjp) throws Throwable {
//获取日志对象
Logger logger = Logger.getLogger(MyAop.class);
//获取方法名和参数
Object proceed = pjp.proceed();
if (proceed != null) { //目标方法执行成功,则记录日志
String name = pjp.getSignature().getName();//目标方法参数
Object[] args = pjp.getArgs();//目标方法参数
String argsStr = Arrays.toString(args);
logger.info("在这个时间:" + new Date() + "执行了:" + name + "方法,传递的参数:" + argsStr);
}
}
}
5.4dao 层接口
5.5 dao实现类
5.6 log4j.proerties
#日志级别debug<info<warn<error
log4j.rootLogger=INFO, Console ,File
#输出到控制台
#Console
log4j.appender.Console=org.apache.log4j.ConsoleAppender
log4j.appender.Console.layout=org.apache.log4j.PatternLayout
log4j.appender.Console.layout.ConversionPattern=%d [%t] %-5p [%c] - %m%n
#输出到文件# org.apache.log4j.FileAppender
#File
log4j.appender.File =org.apache.log4j.DailyRollingFileAppender
log4j.appender.File.File = c://class/log.log
log4j.appender.File.layout = org.apache.log4j.PatternLayout
log4j.appender.File.layout.ConversionPattern =%d [%t] %-5p [%c] - %m%n
5.7测试
public class UserTest {
UserService service;
@Before //在执行UserTest 类中其他方法时,该方法先执行
public void init(){
ApplicationContext context = new ClassPathXmlApplicationContext("spring.xml");
service = context.getBean(UserService.class);
}
@Test
public void deleteById() {
service.deleteById(2);
}
@Test
public void update() {
User user = service.get(4);
user.setName("八戒");
service.update(user);
}
}
5.7效果
5.7.1控制台打印
5.7.2 日志文件
6小结
自定义注解+aop的步骤:
1.开发自定义注解
2.开发aop,并在切点处使用自定义注解的全路径名
3.在目标方法上标注自定义注解