导入
aopalliance-1.0.jar
aspectjrt-1.7.4.jar
aspectjweaver-1.7.4.jar
Spring AOP 的使用可以注解或是xml配置文件的形式,使用AOP尽量使用注解的形式
AOP注解的方式
定义切面和连接点 LogAspect
package com.shpun.aop;
import org.aspectj.lang.annotation.*;
@Aspect
public class LogAspect {
/*
或使用@Pointcut,不用每个都写那么长的类名
@Pointcut("execution(* com.shpun.service..*(..))")
public void print(){}
@Before("print()")
@After("print()")
@AfterReturning("print()")
@AfterThrowing("print()")
*/
// 切入点为 com.shpun.service包下的所有类的所有方法
// 在被代理对象的方法 前 先调用
@Before("execution(* com.shpun.service..*(..))")
public void before(){
System.out.println("LogAspect before ... ");
}
// 在被代理对象的方法 后 调用
@After("execution(* com.shpun.service..*(..))")
public void after(){
System.out.println("LogAspect after ... ");
}
// 在被代理对象的方法 正常返回 后调用
@AfterReturning("execution(* com.shpun.service..*(..))")
public void afterReturning(){
System.out.println("LogAspect afterReturning ... ");
}
// 在被代理对象的方法 抛出异常 后调用
@AfterThrowing("execution(* com.shpun.service..*(..))")
public void afterThrowing(){
System.out.println("LogAspect afterThrowing ... ");
}
}
接口和实现类
package com.shpun.service;
public interface ShowService {
void showCustomer(Customer customer);
}
package com.shpun.service;
@Service
public class ShowServiceImpl implements ShowService {
@Override
public void showCustomer(Customer customer) {
System.out.println("ShowServiceImpl : id: "+customer.getId()+" name: "+customer.getName()+" note: "+customer.getNote());
}
}
JavaBean
package com.shpun.entity;
public class Customer {
private String id;
private String name;
private String note;
/*getter setter*/
}
纯注解的方式使用,需要写一个配置类进行配置
package com.shpun.aop;
@Configuration
@EnableAspectJAutoProxy
@ComponentScan("com.shpun.service")
public class AOPConfig {
@Bean
public LogAspect getLogAspect(){
return new LogAspect();
}
}
或者是使用xml配置文件配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
">
<!-- 扫描com.shpun下注解 -->
<context:component-scan base-package="com.shpun"/>
<!-- 自动代理 -->
<aop:aspectj-autoproxy/>
</beans>
测试
public class TestAOP {
public static void main(String[] main){
ApplicationContext context = new AnnotationConfigApplicationContext(AOPConfig.class);
//ApplicationContext context = new ClassPathXmlApplicationContext("spring-config.xml");
ShowService showServiceImpl = context.getBean(ShowService.class);
Customer customer = new Customer();
customer.setId("1");
customer.setName("AOP");
customer.setNote("AOP Test");
showServiceImpl.showCustomer(customer);
System.out.println("测试异常情况");
customer = null;
showServiceImpl.showCustomer(customer);
}
}
输出结果
ShowServiceImpl : id: 1 name: AOP note: AOP Test
LogAspect after ...
LogAspect afterReturning ...
测试异常情况
LogAspect before ...
LogAspect after ...
LogAspect afterThrowing ...
再使用Around,在LogAspect添加
@Around("execution(* com.shpun.service..*(..))")
public void around(ProceedingJoinPoint jp){
System.out.println("around before ...");
try{
jp.proceed();
}catch (Throwable e){
e.printStackTrace();
}
System.out.println("around after ...");
}
输出结果
around before ...
LogAspect before ...
ShowServiceImpl : id: 1 name: AOP note: AOP Test
around after ...
LogAspect after ...
LogAspect afterReturning ...
测试异常情况
around before ...
LogAspect before ...
around after ...
LogAspect after ... java.lang.NullPointerException
LogAspect afterReturning ...
ps:
当我有多个ShowService的实现类时,比如多一个实现类ShowServiceTwoImpl,并加上@Service
1.如果实现类ShowServiceTwoImpl,class没加上@Service,继续使用如下方式获取bean,则获取的是ShowServiceImpl;加上@Service,则会得到异常,原因是有两个实现类,Spring不知获取哪一个
ShowService showServiceImpl = context.getBean(ShowService.class);
NoUniqueBeanDefinitionException: No qualifying bean of type 'com.shpun.service.ShowService'
available: expected single matching bean but found 2: showServiceImpl,showServiceTwoImpl
2.搜索结果显示该错误多是@Autowired是出现,有的说是Spring没有扫描到,但我换成xml形式扫描,错误一样。未知
ShowService showServiceImpl = context.getBean(ShowServiceImpl.class);
NoSuchBeanDefinitionException: No qualifying bean of type 'com.shpun.service.ShowServiceImpl' available
3.因为@Service默认使用类名首字母小写的形式生成bean,尝试类名查找
ShowService showServiceImpl = context.getBean("showServiceImpl",ShowServiceImpl.class);
BeanNotOfRequiredTypeException: Bean named 'showServiceImpl' is expected to be of type 'com.shpun.service.ShowServiceImpl'
but was actually of type 'com.sun.proxy.$Proxy21'
BeanNotOfRequiredTypeException 切面异常
目前使用的是配置类的形式,所以在AOPConfig里面
@EnableAspectJAutoProxy(proxyTargetClass = true)
若使用xml配置文件的形式,改为
<aop:aspectj-autoproxy proxy-target-class="true"/>
测试AOP成功
ShowService showServiceImpl = context.getBean("showServiceImpl",ShowServiceImpl.class);
ShowService showServiceTwoImpl = context.getBean("showServiceTwoImpl",ShowServiceTwoImpl.class);
输出结果
LogAspect before ...
ShowServiceImpl : id: 1 name: AOP note: AOP Test
LogAspect after ...
LogAspect afterReturning ...
LogAspect before ...
two com.shpun.entity.Customer@7c83dc97
LogAspect after ...
LogAspect afterReturning ...
测试异常情况
LogAspect before ...
LogAspect after ...
LogAspect afterThrowing ...
一个接口的多个实现类,通过getBean使用时,需要proxy-target-class="true"。
<aop:aspectj-autoproxy/> 默认jdk代理
<aop:aspectj-autoproxy proxy-target-class="true"/> 设置为true,为cglib代理
网友评论