接口UserService
public interface UserService {
public void add();
public void delete();
public void update();
public void query();
}
实现类UserServiceImpl
public class UserServiceImpl implements UserService{
public void add() {
System.out.println("增加了一个用户");
}
public void delete() {
System.out.println("删除了一个用户");
}
public void update() {
System.out.println("更新了一个用户");
}
public void query() {
System.out.println("查询了一个用户");
}
}
增加两个需要切入原有代码的类:
Log类是实现了MethodBeforeAdvice接口,该接口实现的方法会在切入类的方法执行前执行
AfterLog类实现了AfterReturningAdvice接口,在切入类执行方法后才执行
public class Log implements MethodBeforeAdvice {
/*
method:要执行的目标对象的方法
objects:参数
o:target目标对象
*/
@Override
public void before(Method method, Object[] objects, Object o) throws Throwable {
assert o != null;
System.out.println(o.getClass().getName()+"的"+method+"被执行了");
}
}
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);
}
}
前期准备就绪,接下来是...
实现方式一:通过API接口实现(切入点)
先在xml文件中注册bean:
<?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: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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.edu.zut.service.UserServiceImpl"/>
<bean id="log" class="com.edu.zut.log.Log"/>
<bean id="afterLog" class="com.edu.zut.log.AfterLog"/>
</beans>
然后配置aop:
<aop:config>
<!-- 切入点-->
<!-- execution里是要执行的位置 execution(修饰符匹配&返回值类型 类的匹配 参数匹配&抛出异常匹配)-->
<aop:pointcut id="pointcut" expression="execution(* com.edu.zut.service.UserServiceImpl.*(..))"/>
<!-- 执行环绕增加-->
<!-- 将advice-ref的东西切入pointcut-ref的地方-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
完整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: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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="userService" class="com.edu.zut.service.UserServiceImpl"/>
<bean id="log" class="com.edu.zut.log.Log"/>
<bean id="afterLog" class="com.edu.zut.log.AfterLog"/>
<aop:config>
<!-- 切入点-->
<!-- execution里是要执行的位置 execution(修饰符匹配&返回值类型 类的匹配 参数匹配&抛出异常匹配)-->
<aop:pointcut id="pointcut" expression="execution(* com.edu.zut.service.UserServiceImpl.*(..))"/>
<!-- 执行环绕增加-->
<!-- 将advice-ref的东西切入pointcut-ref的地方-->
<aop:advisor advice-ref="log" pointcut-ref="pointcut"/>
<aop:advisor advice-ref="afterLog" pointcut-ref="pointcut"/>
</aop:config>
</beans>
Test测试类(注意创建bean对象的时候要使用接口类型,因为动态代理代理的是接口,否则会报错.因为AOP就实现了动态代理的功能):
public class AOPTest {
@Test
public void t1(){
ApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
//必须使用接口,因为动态代理代理的是接口
UserService userService = context.getBean("userService", UserService.class);
userService.add();
}
}
结果:
实现方式二:通过自定义类实现(切面)
增加一个新的类(非常干净的类)
public class DiyPointcut {
public void before(){
System.out.println("方法执行前");
}
public void after(){
System.out.println("方法执行后");
}
}
更改xml文件的aop部分
<bean id="diy" class="com.edu.zut.util.DiyPointcut"/>
<aop:config>
<aop:aspect ref="diy">
<aop:pointcut id="pointcut" expression="execution(* com.edu.zut.service.UserServiceImpl.*(..))"/>
<!-- method指定的方法在pointcut切面执行-->
<aop:before method="before" pointcut-ref="pointcut"/>
<aop:after method="after" pointcut-ref="pointcut"/>
</aop:aspect>
</aop:config>
测试文件同方法一,测试结果如下
实现方式三:通过注解实现(缺点:要写好多次切点)
标注这个类是一个切面
无非就是把原本在xml里配置的内容写到注解里了
@Aspect
public class Anno {
@Before("execution(* com.edu.zut.service.UserServiceImpl.*(..))")
public void before(){
System.out.println("方法执行前");
}
@After("execution(* com.edu.zut.service.UserServiceImpl.*(..))")
public void after(){
System.out.println("方法执行后");
}
}
记得在xml中注册这个类,然后添加注解功能
<bean id="anno" class="com.edu.zut.util.Anno"/>
<aop:aspectj-autoproxy/>
接下来可以增加一个环绕功能(个人觉得很牛逼):
在Anno类中添加一个方法:
@Around("execution(* com.edu.zut.service.UserServiceImpl.*(..))")
public void around(ProceedingJoinPoint jp) throws Throwable {
System.out.println("环绕前");
Object proceed = jp.proceed();//执行方法
System.out.println("针不戳!");
System.out.println("环绕后");
}
执行方法(可以看到输出的语句按照顺序环绕在目标方法周围):