AOP——实现

AOP

AOP作为Spring中核心的部分,重点研究一下。其实AOP的概念不难,主要就是为了降低解耦度然后减少代码的冗余。
日志一般使用的是AOP计数,类似下面这张图
在这里插入图片描述

1.1 AOP的底层原理

AOP的底层原理,动态代理

  • 动态代理的代理类是动态生成的,不是直接写好的!
  • 动态代理分为两大类:基于接口的动态代理,基于类的动态代理
    • 基于接口——JDK动态代理
    • 基于类:cglib类
    • java字节码实现:javasist
      需要了解两个类:Proxy: 代理类,InvocationHandler : 调用处理程序
//Proxy是生成动态代理类,提供了创建动态代理类和实例的静态方法,它也是由这些方法创建的所有动态代理类的超类。
//InvocationHandler-- invoke 调用处理程序并返回接口, 是由代理实例的调用处理程序实现的接口 。 

1.2 动态代理的实现

1.2.1 cglib技术

比如,现在存在一个UserService类:

public class UserService  {

	public void test() {
		System.out.println("test...");
	}

}

此时,我们new一个UserService对象,然后执行test()方法,结果是显而易见的。
如果我们现在想在不修改UserService类的源码前提下,给test()增加额外逻辑,那么就可以使用动态代理机制来创建UserService对象了,比如:
使用cglib技术

UserService target = new UserService();

// 通过cglib技术
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(UserService.class);

// 定义额外逻辑,也就是代理逻辑,这个是数组
enhancer.setCallbacks(new Callback[]{new MethodInterceptor() {
	@Override
	public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
		System.out.println("before...");
		Object result = methodProxy.invoke(target, objects);
		System.out.println("after...");
		return result;
	}
}});

//里面accept,返回的是new Callback[]数组的下标
enhancer.setCallbackFilter(new CallbackFilter() {
			@Override
			public int accept(Method method) {//返回的数据是上面Callback的下标
				if(method.getName().equals("test")){
					return 0;
				}else{
					return 1;
				}
			}
		});

// 动态代理所创建出来的UserService对象
UserService userService = (UserService) enhancer.create();

// 执行这个userService的test方法时,就会额外会执行一些其他逻辑
userService.test();

得到的都是UserService对象,但是执行test()方法时的效果却不一样了,这就是代理所带来的效果。

上面是通过cglib来实现的代理对象的创建,是基于父子类的,被代理类(UserService)是父类,代理类是子类,代理对象就是代理类的实例对象,代理类是由cglib创建的,对于程序员来说不用关心。

1.2.2 jdk动态代理

jdk本身也提供了一种创建代理对象的动态代理机制,但是它只能代理接口,也就是UserService得先有一个接口才能利用jdk动态代理机制来生成一个代理对象,比如:

public interface UserInterface {
	public void test();
}

public class UserService implements UserInterface {

	public void test() {
		System.out.println("test...");
	}

}

利用JDK动态代理来生成一个代理对象:

UserService target = new UserService();

// UserInterface接口的代理对象
Object proxy = Proxy.newProxyInstance(UserService.class.getClassLoader(), new Class[]{UserInterface.class}, new InvocationHandler() {
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("before...");
		Object result = method.invoke(target, args);
		System.out.println("after...");
		return result;
	}
});

UserInterface userService = (UserInterface) proxy;
userService.test();

如果你把new Class[]{UserInterface.class},替换成new Class[]{UserService.class},允许代码会直接报错:

Exception in thread "main" java.lang.IllegalArgumentException: com.zhouyu.service.UserService is not an interface

表示一定要是个接口。

由于这个限制,所以产生的代理对象的类型是UserInterface,而不是UserService,这是需要注意的。

1.3 AOP的实现

AOP的实现有四种方法

  • 1.经典的基于代理的AOP
  • 2.@AspectJ注解驱动的切面
  • 3.纯POJO切面
  • 4.注入式AspectJ切面

下面我只简单介绍一下自己当前使用的,基于注解的AOP实现
首先先自己定义一个UserService,作为bean


@Component
public class UserService{

	@Value("wbw")
	private String user;

	public void test() {
		//applicationContext.publishEvent("123");
		System.out.println("wbw");
	}


然后添加@Aspect切面注解,其中@Before是指在指定方法前运行。切面类

@Aspect
@Component
public class ZhouyuAspect {


	@Before("execution(public void com.zhouyu.service.UserService.test())")
	public void zhouyuBefore(JoinPoint joinPoint) {
		System.out.println("zhouyuBefore");
		System.out.println("目标方法名为:" + joinPoint.getSignature().getName());
        System.out.println("目标方法所属类的简单类名:" +        joinPoint.getSignature().getDeclaringType().getSimpleName());
        System.out.println("目标方法所属类的类名:" + joinPoint.getSignature().getDeclaringTypeName());
        System.out.println("目标方法声明类型:" + Modifier.toString(joinPoint.getSignature().getModifiers()));
        //获取传入目标方法的参数
        Object[] args = joinPoint.getArgs();
        for (int i = 0; i < args.length; i++) {
            System.out.println("第" + (i+1) + "个参数为:" + args[i]);
        }
        System.out.println("被代理的对象:" + joinPoint.getTarget());
        System.out.println("代理对象自己:" + joinPoint.getThis());
	}

}

主main函数

	AnnotationConfigApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
		UserService userService = (UserService) context.getBean("userService");
		userService.test();

AOP代理输出,展示join point的输出消息

zhouyuBefore
目标方法名为:test
目标方法所属类的简单类名:UserService
目标方法所属类的类名:com.zhouyu.service.UserService
目标方法声明类型:public
被代理的对象:com.zhouyu.service.UserService@480bdb19
代理对象自己:com.zhouyu.service.UserService@480bdb19
wbw

上面是AOP的简单实现,其实还有很多种就没一一写出。

1.3 AOP的概念和专属名词

意思是,AOP中的这些概念不是Spring特有的,不幸的是,AOP中的概念不是特别直观的,但是,如果Spring重新定义自己的那可能会导致更加混乱

  1. Aspect:表示切面,比如被@Aspect注解的类就是切面,可以在切面中去定义Pointcut、Advice等等

  2. Join point:表示连接点,表示一个程序在执行过程中的一个点,比如一个方法的执行,比如一个异常的处理,在Spring AOP中,一个连接点通常表示一个方法的执行。就是被代理的方法

  3. Advice:表示通知,表示在一个特定连接点上所采取的动作。Advice分为不同的类型,后面详细讨论,在很多AOP框架中,包括Spring,会用Interceptor拦截器来实现Advice,并且在连接点周围维护一个Interceptor链。代理逻辑,就是在方法前或后执行的部分

  4. Pointcut:表示切点,切入点,用来匹配一个或多个连接点,Advice与切点表达式是关联在一起的,Advice将会执行在和切点表达式所匹配的连接点上

  5. Introduction:可以使用@DeclareParents来给所匹配的类添加一个接口,并指定一个默认实现

  6. Target object:目标对象,被代理对象

  7. AOP proxy:表示代理工厂,用来创建代理对象的,在Spring Framework中,要么是JDK动态代理,要么是CGLIB代理

  8. Weaving:表示织入,表示创建代理对象的动作,这个动作可以发生在编译时期(比如Aspejctj),或者运行时,比如Spring AOP

下面这个 Pointcut的概念更加清晰,就是切入点,指定哪个方法
Advice就是可以在这个切入点环绕执行自定义的相应代码
在这里插入图片描述
JoinPoint 对象
JoinPoint对象封装了SpringAop中切面方法的信息,在切面方法中添加JoinPoint参数,就可以获取到封装了该方法信息的JoinPoint对象.
常用api:
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值