Spring Aop切面实现的方式:
一、实现Spring中方法执行前接口,和方法执行后接口,来实现日志功能。
1 首先是需要增加日志的业务接口
public interface UserService {
void add();
void delete();
void updata();
void query();
}
2 具体的业务类
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("增加一条数据");
}
@Override
public void delete() {
System.out.println("删除一条数据");
}
@Override
public void updata() {
System.out.println("更新一条数据");
}
@Override
public void query() {
System.out.println("查询一条数据");
}
public void split(){
System.out.println("Split一条数据");
}
}
3 我们在这使用了两种通知,定义两个类,一个是业务操作前置通知和执行完业务的后置通知。
public class BeforeLog implements MethodBeforeAdvice {
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println(target.getClass()+"的"+method.getName()+"被执行了");
}
}
public class AfterLog implements AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("执行了"+method.getName()+"返回了"+ returnValue);
}
}
4 配置xml
<bean id="userservice" class="com.aopx.UserServiceImpl"></bean>
<bean id="mylogger" class="com.aopx.BeforeLog"></bean>
<bean id="afterlog" class="com.aopx.AfterLog"> </bean>
<aop:config>
<!--expression为切入点表达式,可自行百度-->
<aop:pointcut id="point" expression="execution(* com.aopx.UserServiceImpl.*(..))"/>
<!-- 执行环绕-->
<aop:advisor advice-ref="mylogger" pointcut-ref="point"></aop:advisor>
<aop:advisor advice-ref="afterlog" pointcut-ref="point"></aop:advisor>
</aop:config>
5 测试
@Test
public void aoptest(){
ApplicationContext app = new ClassPathXmlApplicationContext("aops.xml");
UserService userservice = app.getBean("userservice", UserService.class);
userservice.add();
}
执行结果为
class com.aopx.UserServiceImpl的add被执行了
增加一条数据
执行了add返回了null
二、自定义类来实现日志功能
1 继续使用上面的业务类和接口
2 自定义切面
public class PointAspect {
public void before(){
System.out.println("方法调用前被执行");
}
public void after(){
System.out.println("方法调用后执行");
}
}
3 XML配置
<bean id="userservice" class="com.aopx.UserServiceImpl"></bean>
<bean id="mylogger" class="com.aopx.BeforeLog"></bean>
<bean id="afterlog" class="com.aopx.AfterLog"> </bean>
<bean id="pointAspect" class="com.aopx.PointAspect"></bean>
<aop:config>
<aop:aspect ref="pointAspect">
<aop:pointcut id="point" expression="execution(* com.aopx.UserServiceImpl.*(..))"/>
<aop:before method="before" pointcut-ref="point"></aop:before>
<aop:after method="after" pointcut-ref="point"></aop:after>
</aop:aspect>
</aop:config>
4 测试
@Test
public void aoptest2(){
ApplicationContext app = new ClassPathXmlApplicationContext("aops.xml");
UserService userservice = app.getBean("userservice", UserService.class);
userservice.add();
}
测试结果
方法调用前被执行
增加一条数据
方法调用后执行
总结两种方式,
第一种方式为了实现前置和后置通知,需要两个类来完成,如果需要其他类型的环绕(异常之类),就的继续创造类来完成,比较重量化;优点是可以获取到被切入的类型和方法名之类的信息。
第二中与第一种刚好相反,比较轻量级,被切入的类型和方法名之类的看不到。
三 使用注入的方式来实现第二种类型的功能
1 继续使用上面的业务类和接口,在UserServiceImpl 类上面加入@Component,进行注入
2 自定义切面
@Component
@Aspect
public class AnnotationPointcut {
@Pointcut("execution(* com.aopx.UserServiceImpl.*(..))")
public void pointCut(){
}
@Before("pointCut()")
public void before(){
System.out.println("注解方式:方法执行前");
}
@After("pointCut()")
public void after(){
System.out.println("注解方式:方法执行后");
}
@Around("pointCut()")
public void around(ProceedingJoinPoint point) throws Throwable {
System.out.println("注解方式: 环绕通知前");
point.proceed();
System.out.println("注解方式:环绕通知后执行");
}
}
3 Xml配置
自动注入bean和自动代理
<context:component-scan base-package="com.aopx"></context:component-scan>
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4 测试
ApplicationContext app = new ClassPathXmlApplicationContext("annotationAop.xml");
UserService useservice = app.getBean("userServiceImpl",UserService.class);
useservice.add();
结果
注解方式: 环绕通知前
注解方式:方法执行前
增加一条数据
注解方式:环绕通知后执行
注解方式:方法执行后
总结:个人认为重要的是 获去业务Bean对象时,只能是接口类型;如果该接口被多5个类实现的话,假如这五个类要有五个切面,在使用注解时后,就要对被环绕的类指定优先级了。如下面的AopTest类,这里的AnnotationPointcut1 、 UserServiceImpl1和前面的AnnotationPointcut 、 UserServiceImpl一样,println里面的内容不同。 UserService userService,必须是接口,注入实现类。
@Component
public class AopTest {
@Autowired()
@Qualifier(value = "userServiceImpl")
public UserService userService;
@Autowired()
@Qualifier(value = "userServiceImpl1")
public UserService userService1;
public void aoptest(){
serService.add();
}
public void aoptest1(){
userService1.add();
}
}