在这里我们使用的是springboot框架,需要加入AOP的依赖;
如下:
<!-- 使用切面编程-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
然后我们编写一个切面类;
@Component
@Aspect
public class ValidUserNameAspect {
//切入点(这个切点是针对于注解的)
@Pointcut("@annotation(com.jeecms.annotation.ValidUserName)")
public void validUserName() {
}
//切入点(这个切点需要使用execution表达式了)
@Pointcut(value = "execution(* com.jeecms.controller.*.*(..))")
public void excServerPonit() {
}
//使用场景
@Before(value="@annotation(validUserName)")
public Object ValidUser(JoinPoint joinPoint,ValidUserName validUserName) {
//获取方法上的所有参数
Object[] arguments = joinPoint.getArgs();
for (Object object : arguments) {
System.out.println(object);
}
String value = validUserName.value();
System.out.println(value);
return true;
}
}
然后讲解一下
1.首先我们需要将这个类加上@Aspect这个注解,表示这是一个切面类,@Component这个注解也是必须的,把普通pojo实例化到spring容器中
2.定义切点需要用到@Pointcut,这里说明一下Execution切点函数
这里这篇写的蛮好的,可以看看这个,链接:https://blog.csdn.net/yangshangwei/article/details/77627825
这个讲切点函数比较详细;
https://blog.csdn.net/autfish/article/details/51184405,这篇有讲到更多的切点函数以及逻辑运算,也很好;
重点:参数部分允许使用通配符:
* 匹配任意字符,但只能匹配一个元素
.. 匹配任意字符,可以匹配任意多个元素,表示类时,必须和*联合使用
+ 必须跟在类名后面,如Horseman+,表示类本身和继承或扩展指定类的所有类
3.@Before这个注解就是切面的通知注解,表示在执行方法之前,叫前置通知,还有其他的通知如下:
@After: 后置通知, 在方法执行之后执行 。
@AfterRunning: 返回通知, 在方法返回结果之后执行
@AfterThrowing: 异常通知, 在方法抛出异常之后
@Around: 环绕通知, 围绕着方法执行,环绕通知方法可以包含上面四种通知方法,环绕通知的功能最全面。环绕通知需要携带 ProceedingJoinPoint 类型的参数,且环绕通知必须有返回值, 返回值即为目标方法的返回值。在切面类中创建环绕通知方法
具体可以看如下链接:
https://blog.csdn.net/u010502101/article/details/78823056
4.关于AOP的原理
可以查看这篇文章:https://juejin.im/post/591d8c8ba22b9d00585007dd,也是自己照着撸的,有更深的体会;
讲到了代理模式,
静态代理:静态代理产生于代码编译阶段,编译完成后就不能修改了,Iperson就是一个接口,Person类实现了这个接口
我们在创建PersonProxy这个类的时候把person注入构造函数,就能通过这个代理获取到Person类的方法了;
package com.jeecms.proxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 使用静态代理类(局限性:需要固定的类编写接口(或许还可以接受,毕竟有提倡面向接口编程),需要实现接口的每一个函数(不可接受),同样会造成代码的大量重复,将会使代码更加混乱。)
* @author jinlei
*
*/
public class PersonProxy {
private Iperson iPerson;
private final static Logger logger = LoggerFactory.getLogger(PersonProxy.class);
public PersonProxy(Iperson iPerson) {
this.iPerson = iPerson;
}
public void doSomething() {
logger.info("Before Proxy");
iPerson.doSomething();
logger.info("After Proxy");
}
public static void main(String[] args) {
PersonProxy personProxy = new PersonProxy(new Person());
personProxy.doSomething();
}
}
jdk自带的动态代理模式可以看看这个:https://blog.csdn.net/lovejj1994/article/details/78080124
package com.jeecms.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* JDK自带的动态代理
* 使用Java反射机制,它的好处理时可以为我们生成任何一个接口的代理类,并将需要增强的方法织入到任意目标函数。
* 但它仍然具有一个局限性,就是只有实现了接口的类,才能为其实现代理。
* @author jinlei
*
*/
public class PersonProxyjdk implements InvocationHandler{
private Object obj;
private final Logger logger = LoggerFactory.getLogger(this.getClass());
public Object bind(Object obj) {
this.obj = obj;
return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
logger.info("Before Proxy");
result = method.invoke(obj, args);
logger.info("After Proxy");
} catch (Exception e) {
throw e;
}
return result;
}
public static void main(String[] args) {
PersonProxyjdk personProxy = new PersonProxyjdk();
Iperson iperson = (Iperson) personProxy.bind(new Person());
iperson.getSomething();
iperson.doSomething();
}
}
cglib动态代理模式可以看看这个:https://blog.csdn.net/Q_AN1314/article/details/79724334
package com.jeecms.proxy;
import java.lang.reflect.Method;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
/**
* CGLIB解决了动态代理的难题,它通过生成目标类子类的方式来实现来实现代理,而不是接口,规避了接口的局限性。
* CGLIB是一个强大的高性能代码生成包(生成原理还没研究过),其在运行时期(非编译时期)生成被 代理对象的子类,并重写了被代理对象的所有方法,从而作为代理对象。
当然CGLIB也具有局限性,对于无法生成子类的类(final类),肯定是没有办法生成代理子类的
* @author jinlei
*
*/
public class PersonProxycglib implements MethodInterceptor{
private final Logger logger = LoggerFactory.getLogger(this.getClass());
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
logger.info("Before Proxy");
Object result = methodProxy.invokeSuper(proxy, args);
logger.info("After Proxy");
return result;
}
public static Person getProxyInstance() {
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(Person.class);
enhancer.setCallback(new PersonProxycglib());
return (Person) enhancer.create();
}
public static void main(String[] args) {
PersonProxycglib sf = new PersonProxycglib();
Person sd = sf.getProxyInstance();
sd.getSomething();
}
}
记录下来,防止遗忘。如果能帮到各位,那就更好了