1.Aop介绍
AOP术语解释: AOP概念| ProcessOn免费在线作图,在线流程图,在线思维导图
- AOP要实现的是在我们原来的写代码的基础上进行一定的包装,如在方法执行前,方法返回后,方法抛出异常后等进行一定的拦截处理或者叫做增强处理。
- Aop是基于动态代理来实现的
默认的,如果使用接口,用JDK提供的动态代理实现,如果没有实现接口,使用CGlib实现,在spring3.2之后,spring-core直接就把CGLIB和ASM的源码包括进来了,这也是为什么我们不需要显示的引入这两个依赖的原因。
在Spring框架中,SpringAOP要依赖于SpringIOC来管理,它只能作用Spring容器中的bean,它时使用纯粹的Java代码来实现的,只能作用于bean的方法,
SpringAOP底层是基于动态代理的:分为JDK动态代理和Cglib动态代理,Spring底层对着这两者都进行了封装。
Spring 把CgLib那一套项目引进来了
代理对象执行被代理对象的方法,在执行被代理类的方法的时候,会先通过拦截器,进入到
代理类是由cglib创建的,我们来说不用关心怎么创建代理类的。
- 基于cglib来实现代理对象的创建,是基于父子类的,被代理对象(UserService)是父类,代理类是子类,有从cglib创建。
- 基于jdk来实现代理对象的创建,是基于接口来实现的动态代理技术,只能代理接口,也就是UserService得现有一个接口才能利用jdk实现动态代理:
public interface UserInterface{
public void test();
}
//UserService实现接口,重写test()方法
public class UserService implements UserService{
public void test(){
System.out.printlnj("test...");
}
}
UserService实现接口UserInterface,接着就可以利用动态代理来生成代理对象:
//创建一个被代理对象target
UserService target = new UserService();
//UserInterface接口的代理对象,Userinterface.class,不能换成UserService.class,否则会报错
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
2. ProxyFactory
上面介绍了两种动态代理技术,在Spring中对他们进行了封装,是我们不用关心到底是使用cglib和jdk动态代理,在Spring中是通过ProxyFactory工厂进行封装的
UserService target = new UserService();
ProxyFactory proxyFactory = new ProxyFactory();
proxyFactory.setTarget(target);
proxyFactory.addAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before...");
Object result = invocation.proceed();
System.out.println("after...");
return result;
}
});
UserInterface userService = (UserInterface) proxyFactory.getProxy();
userService.test();
ProxyFactory会帮我们去判断,如果UserService实现了接口,那么ProxyFactory底层就会用jdk动态代理,如果没有实现接口,就会用cglib技术,上面的代码,就是由于UserService实现了UserInterface接口,所以最后产生的代理对象是UserInterface类型。
3.创建代理对象的方式
怎么直接从Spring容器中得到UserService的代理对象,让ProxyFactory 产生的代理对象直接就是Spring的bean,这个过程需要我们开发者告诉Spring,哪些类需要被代理,代理的逻辑是什么。
- ProxyFactoryBean
这种方式来定义的UserService的bean,是经过AOP的但是这种方式只能针对某一个Bean他是一个工厂Bean,所以利用的就是工厂bean的技术,简接将UserService的代理对象设置成了Bean
@Bean
public ProxyFactoryBean userServiceProxy(){
UserService userService = new UserService();
ProxyFactoryBean proxyFactoryBean = new ProxyFactoryBean();
proxyFactoryBean.setTarget(userService);
proxyFactoryBean.addAdvice(new MethodInterceptor() {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("before...");
Object result = invocation.proceed();
System.out.println("after...");
return result;
}
});
return proxyFactoryBean;
}
BeanNameAutoProxyCreator
ProxyFactoryBean得自己指定被代理的对象,那么我们可以通过BeanNameAutoProxyCreator来通过指定某个bean的名字,来对该bean进行代理
@Bean
public BeanNameAutoProxyCreator beanNameAutoProxyCreator() {
BeanNameAutoProxyCreator beanNameAutoProxyCreator = new BeanNameAutoProxyCreator();
beanNameAutoProxyCreator.setBeanNames("userSe*");
beanNameAutoProxyCreator.setInterceptorNames("zhouyuAroundAdvise");
beanNameAutoProxyCreator.setProxyTargetClass(true);
return beanNameAutoProxyCreator;
}
通过BeanNameAutoProxyCreator可以对批量的Bean进行AOP,并且指定了代理逻辑,指定了一个InterceptorName,也就是一个Advise,前提条件是这个Advise也得是一个Bean,这样Spring才能找到的,但是BeanNameAutoProxyCreator的缺点很明显,它只能根据beanName来指定想要代理的Bean。
DefaultAdvisorAutoProxyCreator
@Bean
public DefaultPointcutAdvisor defaultPointcutAdvisor(){
NameMatchMethodPointcut pointcut = new NameMatchMethodPointcut();
pointcut.addMethodName("test");
DefaultPointcutAdvisor defaultPointcutAdvisor = new DefaultPointcutAdvisor();
defaultPointcutAdvisor.setPointcut(pointcut);
defaultPointcutAdvisor.setAdvice(new ZhouyuAfterReturningAdvise());
return defaultPointcutAdvisor;
}
@Bean
public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator() {
DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator = new DefaultAdvisorAutoProxyCreator();
return defaultAdvisorAutoProxyCreator;
}
通过DefaultAdvisorAutoProxyCreator会直接去找所有Advisor类型的Bean,根据Advisor中的PointCut和Advice信息,确定要代理的Bean以及代理逻辑。
但是,我们发现,通过这种方式,我们得依靠某一个类来实现定义我们的Advisor,或者Advise,或者Pointcut,那么这个步骤能不能更加简化一点呢?
对的,通过注解!
比如我们能不能只定义一个类,然后通过在类中的方法上通过某些注解,来定义PointCut以及Advice,可以的,比如:
@Aspect
@Component
public class RuozhuoAspect{
@Before("excution(public void com.ruozhuo.service.UserService.test())")
public void ruozhuoBefore(JoinPoint joinpoint){
System.out.println("ruozhuoBefore");
}
}
通过上面这个类,我们就直接定义好了所要代理的方法(通过一个表达式),以及代理逻辑(被@Before修饰的方法),简单明了,这样对于Spring来说,它要做的就是来解析这些注解了,解析之后得到对应的Pointcut对象、Advice对象,生成Advisor对象,扔进ProxyFactory中,进而产生对应的代理对象,具体怎么解析这些注解就是**@EnableAspectJAutoProxy注解**所要做的事情了,后面详细分析。