欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

spring的aop实现

程序员文章站 2022-07-12 15:20:40
...

前言:
spring的aop是spring框架中很重要的功能,提供了一个面向切面的实现方式,从而实现了诸如日志,事务,拦截等切面的实.由于spring已经整合了一个aop框架AspectJ,因此我们既可以用spring的代理工厂方式,也可直接使用AspectJ框架的方式来实现切面功能,并且AspectJ框架的实现也有两种,因此总的来说由三种实现方式。

一.基于spring的ProxyFactoryBean实现aop
由于面向切面的实现方式是基于动态代理的方式,因此spring提供了一个代理工厂的bean,利用这个bean我们可以实现一些切面功能.同时spring为我们提供大量的通知的接口,只要我们实现这些接口就可以实现一个切面功能.
spring的aop实现
这里先实现一个前置的通知接口(注意通知也是bean):

@Component
public class Advice implements MethodBeforeAdvice{
    /**
     * arg0:被调用的方法
     * arg1:这个方法的参数
     * arg2:被代理的对象
     */
    @Override
    public void before(Method arg0, Object[] arg1, Object arg2) throws Throwable {
        System.out.println("拦截方法:"+arg0.getName());

    }

}

实现了通知那么之后就是要设计代理的过程。这里就用这个类来模拟一个service

public interface Service {
    public void show();
}
@Component("serviceImp")
public class ServiceImp implements Service{
    @Override
    public void show() {
        System.out.println("执行方法");
    }

}

现在的关键就是在于设计ProxyFactoryBean

<bean id="proxyFactoryBean" class="org.springframework.aop.framework.ProxyFactoryBean">
    <!-- 代理的接口,如果目标对象没有接口的话就会用cglib来实现 -->
        <property name="ProxyInterfaces">   
            <list>
                <value>service.Service</value>
            </list>
        </property>
        <!-- 目标对象 -->
        <property name="target" ref="serviceImp"></property>
        <!-- 通知的bean -->
        <property name="interceptorNames">
            <list>
                <value>advice</value>
            </list>
        </property>
    </bean> 

当这些设计好后便可以实现对方法的增强,来看看实现:

public void aopByFactory() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring/spring.xml");
        //由于上面是有接口的因此不会用cglib实现,固需要用接口
        Service service = (Service) applicationContext.getBean("proxyFactoryBean");
        System.out.println(service.getClass());
        service.show();
    }

结果:
spring的aop实现
可以看到确实实现了.
2基于aspectj框架实现
第一种方式比较简单,直接利用注解便可以实现,不过要注意Apsect的注解需要导Aspect的jar包.导入了包后我们便可以自己设置通知类,这里设计了一个简单的通知类

@Component
@Aspect
public class AdviceByAnnotation {

    @Before("execution(* service.*.*())")
    public void before(){
        System.out.println("基于注解实现aspect");
    }
}

关于execution表达式可以去看看其他的博客,这里是拦截service包下任意类的任意方法。
同时再spring的配置文件种需要开启对apsect注解的识别功能

    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>

现在来看看测试代码

    public void aopByannotionAspectj() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring/spring.xml");
        Service service = applicationContext.getBean(Service.class);
        System.out.println(service.getClass());
        service.show();
        //这里额外写了一个没有接口的类,可以看到是用cglib实现
        ServiceBycglib  imp = applicationContext.getBean(ServiceBycglib.class);
        System.out.println("spring aop 利用cglib代理未实现接口的类:" +imp.getClass());

    }

结果:
spring的aop实现
这种实现方式相对普遍
利用spring配置文件整合实现aspectj
这种方式不需要导入aspectj的jar包既可以实现,实现上来说也不复杂.首先还是要有一个通知类:

@Component
public class AdivceByXml {
    public void before() {
        System.out.println("基于xml配置aspectj实现aop");
    }
}

然后便是xml的配置

        <!-- 基于xml实现 -->
      <aop:config>
      <!-- 设置切入点 -->
        <aop:pointcut expression="execution(* service.*.*(..))" id="pointcut"/>
        <!-- 设置切面 -->
        <aop:aspect id="myAspect" ref="adivceByXml" >
                 <aop:before method="before" pointcut-ref="pointcut"/>      
        </aop:aspect>
    </aop:config>

这里spring提供了专门的标签用于设置aop,注意要设置pointcut(切入点),和切面。当然还有很多的通知类型这里只用了before。测试代码:

    public void aopByXml() {
        ApplicationContext applicationContext = new ClassPathXmlApplicationContext("spring/spring.xml");
        Service service = applicationContext.getBean(Service.class);
        System.out.println(service.getClass());
        service.show();
    }

结果:
spring的aop实现
可以看到aspectj的两种实现方式都可以,不过第二种再设计事务的时候会方便许多

相关标签: spring aop