spring的aop实现
前言:
spring的aop是spring框架中很重要的功能,提供了一个面向切面的实现方式,从而实现了诸如日志,事务,拦截等切面的实.由于spring已经整合了一个aop框架AspectJ,因此我们既可以用spring的代理工厂方式,也可直接使用AspectJ框架的方式来实现切面功能,并且AspectJ框架的实现也有两种,因此总的来说由三种实现方式。
一.基于spring的ProxyFactoryBean实现aop
由于面向切面的实现方式是基于动态代理的方式,因此spring提供了一个代理工厂的bean,利用这个bean我们可以实现一些切面功能.同时spring为我们提供大量的通知的接口,只要我们实现这些接口就可以实现一个切面功能.
这里先实现一个前置的通知接口(注意通知也是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();
}
结果:
可以看到确实实现了.
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配置文件整合实现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();
}
结果:
可以看到aspectj的两种实现方式都可以,不过第二种再设计事务的时候会方便许多
上一篇: jQuery实现瀑布流
下一篇: recyclerview实现瀑布流