学习地址:慕课网
AOP
面向切面编程是一种编程范式,用来解决特定问题,是OOP的补充
使用初衷
AOP使用场景
1-权限案例对比
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
普通方法拦截
校验权限的一个例子
@Service
public class ProductService {
@Autowired
AuthService authService;
public void insert(Product product){
authService.checkAccess();//代码有侵入
System.out.println("insert product");
}
public void delete(Long id){
authService.checkAccess();
System.out.println("delete product");
}
}
AOP拦截方式
定义一个在方法上的注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface AdminOnly {
}
在目标方法上加入注解
@AdminOnly
public void insert(Product product){
//authService.checkAccess();代码有侵入
System.out.println("insert product");
}
@AdminOnly
public void delete(Long id){
//authService.checkAccess();
System.out.println("delete product");
}
声明一个
AOP
,配置拦截规则
@Aspect
@Component
public class SecurityAspect {
@Autowired
AuthService authService;
@Pointcut("@annotation(AdminOnly)")
public void adminOnly(){
}
@Before("adminOnly()")//方法之前执行
public void check(){
authService.checkAccess();
}
}
相对于普通方法,
AOP
的方式减少了重复代码,降低了代码耦合,更低的代码侵入性。
2-SpringAOP使用详解
@Aspect
表示类是一个切面类
@Pointcut
表示切面的作用范围
Advice
表示作用的时间点,before、after
designators
匹配的方式
wildcards
匹配的通配符
*
匹配任意数量的字符
+
匹配制定类及其子类
..
一般用于匹配任意数的子包或参数
operators
运算符
execution类型
@Aspect
@Component
public class ExecutionAspectConfig {
//@Pointcut("execution(public * com.imooc.aopdemo.service.*Service.*(..))") 不拦截子包
//@Pointcut("execution(public * com.imooc.aopdemo.service..*Service.*(..))")
//@Pointcut("execution(public void com.imooc.aopdemo.service..*Service.*(..))") //匹配返回值为void的方法
//@Pointcut("execution(public * com.imooc.aopdemo.service..*Service.*(Long))") //匹配第一个参数为Long的方法
//@Pointcut("execution(public * com.imooc.aopdemo.service..*Service.*())") //匹配没有参数的方法
@Pointcut("execution(public * com.imooc.aopdemo.service..*Service.*(..) throws IllegalAccessException)") //匹配抛出异常的方法
public void matchCondition(){
}
@Before("matchCondition()")
public void before(){
System.out.println("");
System.out.println("***before***");
}
}
within类型
@Aspect
@Component
public class PkgTypeAspectConfig {
//@Pointcut("within(com.imooc.aopdemo.service.ProductService)")匹配类里的所有方法
@Pointcut("within(com.imooc.aopdemo.service..*)")//匹配ProductService类里头的所有方法
public void matchType(){}
@Before("matchType()")
public void before(){
System.out.println("");
System.out.println("***before***");
}
}
对象匹配
arget
与this
的区别:
this
能够拦截AOP
的introduction
定义的方法,而target
不行(因为intrduction
定义的方法是经过AOP
代理过后动态添加的)
参数匹配
注解匹配
@Aspect
@Component
public class AnnoAspectConfig {
//@Pointcut("@annotation(com.imooc.aopdemo.anno.AdminOnly)")
//@Pointcut("@within(com.imooc.aopdemo.anno.NeedSecured) && within(com.imooc.aopdemo..*)")
//@Pointcut("@target(com.imooc.aopdemo.anno.NeedSecured) && within(com.imooc.aopdemo..*)")
@Pointcut("@args(com.imooc.aopdemo.anno.NeedSecured) && within(com.imooc.aopdemo..*)")
public void matchCondition(){
}
@Before("matchCondition()")
public void before(){
System.out.println("");
System.out.println("***before***");
}
}
advice注解
@Aspect
@Component
public class AdviceConfig {
@Pointcut("@annotation(com.imooc.aopdemo.anno.AdminOnly)")
public void matchAnno(){}
@Pointcut("execution(* *..find*(Long,..))")
public void matchLongArg(){}
@Pointcut("execution(* *..*(..)throws IllegalAccessException)")
public void matchException(){}
@Pointcut("execution(String com.*..*(..))")
public void matchReturn(){}
@Pointcut("execution(* com.*..*(..))")
public void matchAll(){}
// @Around("matchReturn()")
// public void around(ProceedingJoinPoint joinPoint){
// try{
// Object res = joinPoint.proceed(joinPoint.getArgs());
// System.out.println("==========return data:"+res);
// } catch (Throwable throwable) {
// throwable.printStackTrace();
// } finally {
// System.out.println("===========finally================");
// }
// }
// @Before("matchLongArg() && args(ww,..)")
// public void before(long ww){
// System.out.println("==========the data:"+ww);
// }
@AfterThrowing("matchException()")
public void after(){
System.out.println("=========after========");
}
}
3-SpringAOP实现原理
代理模式(静态代理)
接口
public interface Subject {
void request();
}
目标对象
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("real subject excute request");
}
}
代理对象
public class Proxy implements Subject {
private RealSubject realSubject;
public Proxy(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public void request() {
System.out.println("before");
try {
realSubject.request();
} catch (Exception e) {
System.out.println("ex:"+e.getMessage());
throw e;
}finally {
System.out.println("after");
}
}
}
客户端调用
public class Client {
public static void main(String args[]){
Subject subject = new Proxy(new RealSubject());//通过构造器强行注入
subject.request();
}
}
jdk代理
/**
* jdk动态代理
*
*/
public class JdkProxySubject implements InvocationHandler {
private RealSubject realSubject;
public JdkProxySubject(RealSubject realSubject) {
this.realSubject = realSubject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("before");
Object result = null;
try {
result = method.invoke(realSubject,args);
} catch (Exception e) {
System.out.println("ex:"+e.getMessage());
throw e;
}finally {
System.out.println("after");
}
return result;
}
}
public class Client {
public static void main(String args[]){
Subject subject = (Subject) Proxy.newProxyInstance(Client.class.getClassLoader()
,new Class[]{Subject.class},new JdkProxySubject(new RealSubject()));
subject.request();
}
}
接口增加方法,静态代理需要实现其接口,而动态代理不需要改动代码。
public interface Subject {
void request();
void hello();
}
cglib代理
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class DemoMethodInterceptor implements MethodInterceptor {
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("before in cglib");
Object result = null;
try {
result = methodProxy.invokeSuper(o,objects);
}catch (Exception e){
System.out.println("ex:"+e.getMessage());
throw e;
}finally {
System.out.println("after in cglib");
}
return result;
}
}
public class Client {
public static void main(String args[]){
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(RealSubject.class);
enhancer.setCallback(new DemoMethodInterceptor());
Subject subject = (Subject) enhancer.create();
subject.hello();
}
}
AOP如何链式调用
public abstract class Handler {
private Handler sucessor;
public void execute(){
//链式调用
handleProcess();
if(sucessor != null){
sucessor.execute();
}
}
protected abstract void handleProcess();
public Handler getSucessor() {
return sucessor;
}
public void setSucessor(Handler sucessor) {
this.sucessor = sucessor;
}
}
public class Client {
static class HandlerA extends Handler{
@Override
protected void handleProcess() {
System.out.println("handler by a");
}
}
static class HandlerB extends Handler{
@Override
protected void handleProcess() {
System.out.println("handler by b");
}
}
static class HandlerC extends Handler{
@Override
protected void handleProcess() {
System.out.println("handler by c");
}
}
public static void main(String args[]){
Handler handlerA = new HandlerA();
Handler handlerB = new HandlerB();
Handler handlerC = new HandlerC();
handlerA.setSucessor(handlerB);
handlerB.setSucessor(handlerC);
handlerA.execute();
}
}
第二种方式:
public class Chain {
private List<ChainHandler> handlers;
private int index = 0;
public Chain(List<ChainHandler> handlers) {
this.handlers = handlers;
}
public void proceed(){
if(index >= handlers.size()){
return ;
}
handlers.get(index++).execute(this);
}
}
public abstract class ChainHandler {
public void execute(Chain chain){
handleProcess();
chain.proceed();//执行表下一个Chain
}
protected abstract void handleProcess();
}
public class ChainClient {
static class ChainHandlerA extends ChainHandler{
@Override
protected void handleProcess() {
System.out.println("handle by chain a ");
}
}
static class ChainHandlerB extends ChainHandler{
@Override
protected void handleProcess() {
System.out.println("handle by chain b ");
}
}
static class ChainHandlerC extends ChainHandler{
@Override
protected void handleProcess() {
System.out.println("handle by chain c ");
}
}
static class ChainHandlerD extends ChainHandler{
@Override
protected void handleProcess() {
System.out.println("handle by chain d ");
}
}
public static void main(String args[]){
List<ChainHandler> handlers = Arrays.asList(
new ChainHandlerA(),new ChainHandlerB(),
new ChainHandlerC(),new ChainHandlerD()
);
Chain chain = new Chain(handlers);
chain.proceed();
}
}
Spring AOP注解
对单个数据库操作有事务控制,同一个方法内有多个数据库操作,不加事务注解,各自的事务不会相互影响;加上注解,会加上一个事务包含这些事务,对每个事务进行标记,当所有事务执行完之后,根据标记判断执行还是回滚