SpringAOP

23 阅读3分钟

AOP编程概念

AOP编程也可以称为Spring动态代理开发 概念:通过代理,为原始类增加额外功能

好处:利于原始类的维护

为什么需要引入AOP(动态代理开发呢)

举个简单的例子

在没有引入AOP的时候

像我们业务层也就是Service层,一般适用于完成业务代码和DAO层调用的,但是存在一个问题

有时候我们需要引入日志,性能,我们会在业务层写很多冗余代码,这并不符合程序设计的理念

这其实跟我们生活中的一个例子相似:

上述房东就是找了代理帮他处理他不想干的杂活

由此:我们引入动态代理

AOP的底层就是通过动态代理实现的

AOP编程开发的步骤

  1. 原始对象(例如ServiceImpl)
  2. 额外功能 (日志,性能,事务)
  3. 切入点
  4. 组转切面

1.基于配置文件开发流程

写一个类实现MethodIntercepeter方法

通过实现invoke方法,调用原始类的方法,并且可以在它前后以及抛出异常时引入我们想要增加的功能

通过配置文件配置 aop切面

具体代码如下

public class Around implements MethodInterceptor {  
/**  
* invoke 方法的作用:额外功能书写在invoke,额外功能 可以写在原始方法之前前之后  
* 确定:原始方法怎么运行  
* @param methodInvocation 代表额外功能所增加给的那个原始方法 , methodInvocation.proceed(); 代表原始方法的运行  
* @return 代表原始方法执行后的放回值,  
* @throws Throwable  
*/  
@Override  
public Object invoke(MethodInvocation methodInvocation) throws Throwable {  
//运行额外功能所增加给的按个原始方法  
System.out.println("----------额外功能------");  
Object ret= null;  
  
ret = methodInvocation.proceed();  
  
System.out.println("----------额外功能------");  
return ret;  
}  
}
<bean id="around" class="com.huy.dynamic.Around"></bean>  
<aop:config >  
<!--所有方法加入功能-->  
<aop:pointcut id="pc" expression="execution(* login(..)) or execution(* register(..))"/>  
<!--组装:目的是把切入点与额外功能进行整合-->  
<aop:advisor advice-ref="around" pointcut-ref="pc"></aop:advisor>  
</aop:config>

这样就成功将我们需要增加的功能给引入了

2.通过注解方式

编写一个切面类,注入spring容器,同时配置文件中开启通过注解引入切面

/**  
* 额外功能  
* 切入点  
*/  
@Aspect  
public class MyAspect {  
  
@Pointcut("execution(* login(..)) || execution(* register(..))")  
public void myPointcut(){}  
  
  
@Around(value = "myPointcut()")  
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {  
System.out.println("------aspect- log------");  
Object res = joinPoint.proceed();  
return res;  
}  
  
}
<bean id="userService" class="com.huy.aspect.UserServiceImpl"></bean>  
<!--切面:额外功能 切入点 组转切面-->  
<bean id="around" class="com.huy.aspect.MyAspect"/>  
  
<!--告诉spring基于注解进行AOP编程-->  
<!-- proxy-target-class="true"就会让创建动态代理的方式就是Cglib-->  
<aop:aspectj-autoproxy/>

底层动态代理的实现

一种是JDK的动态代理,一种是Cgilb动态代理方式

JDk的动态代理

image.png

其中类加载器的作用

image.png

    public static void main(String[] args) {
        //1.创建原始对象
        UserService userService=new UserServiceImpl();
        //2.JDK创建动态代理
        UserService userServiceProxy = (UserService) Proxy.newProxyInstance(userService.getClass().getClassLoader(), userService.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                System.out.println("----log------");
                Object ret = method.invoke(userService, args);
                return ret;
            }
        });
        userServiceProxy.login();
    }
}

Cglib动态代理

image.png

CGlib创建动态代理原理:

通过父子继承关系创建代理对象,原始类作为父类,

代理类作为子类,这样既可以保证两者方法一致,调用原始方法,并且增加额外功能

public class TestCjlib {
   public static void main(String[] args) {
      UserService userService=new UserService();
      //通过cjlib方法创建动态代理对象
      //spring已经给我们引入了

      Enhancer enhancer=new Enhancer();
      enhancer.setClassLoader(userService.getClass().getClassLoader());
      enhancer.setSuperclass(userService.getClass());
      MethodInterceptor interceptor=new MethodInterceptor() {
         //等同于InvocationHandler --invoke
         @Override
         public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
            System.out.println("cjlib    log-------");
            Object ret = method.invoke(userService, objects);
            return  ret;
         }
      };
      enhancer.setCallback(interceptor);
      UserService userServiceProxy = (UserService) enhancer.create();
      userServiceProxy.login("suns","1231241");
      userServiceProxy.register("suns","12314");

   }

}

JDK动态代理: Proxy.newProxyInstance()通过接口创建代理的实现类

CGlib动态代理:Enhancer enhancer=new Enhancer(),

enhancer.setClassLoader()

enhancer.setSuperclass()

enhancer.setCallback

enhancer.create()创建代理对象

通过继承父类来创建代理