1.注解实现
第一步:先准备几个javaBean对象
@Controller
public class UserController {
public void test(){
System.out.println("UserController.test");
}
}
@Repository
public class UserDao {
public void test(){
System.out.println("UserDao.test");
}
}
@Service
public class UserService {
public void test(){
System.out.println("UserService.test");
}
}
第二步:定义切面
/**
* Aspect是定义这个类为一个切面
* 切面由:切入点和通知组成
* 切入点:要拦截哪些类的哪些方法
* 通知:定义拦截方法后做什么
*/
@Component
@Aspect
public class LogCut {
/**
* 切入点就用Pointcut("匹配规则")这个注解表示要拦截哪些方法
*常见切入点表达式
* 表达式中的第一个*表示的是方法修饰的范围(public private protected)如果取值是*号,则表示所有范围
* 1.执行所有公共的方法 @Pointcut("execution(public *(..))")
* 2.执行任意的set方法 @Pointcut("execution(* set*(..))")
* 3.设置指定包(com.zks.service)下的任意类的任意方法@Pointcut("execution(* com.zks.service.*.*(..))")
* 4.设置指定包及子包(com.zks.service)下的任意类的任意方法@Pointcut("execution(* com.zks.service..*.*(..))")
*
*/
@Pointcut("execution(* com.zks.service.*.*(..))")
public void cut(){
}
/**
* 声明前置通知,并将通知应用到指定的切入点上
* 目标类方法执行前,执行该通知
*/
@Before(value = "cut()")//通知指向前面的切入点
public void before(){
System.out.println("前置通知");
}
/**
* 声明返回通知,并将通知应用到指定的切入点上
* 目标类执行完后并且没有异常,执行该通知
*/
@AfterReturning(value = "cut()")
public void afterReturn(){
System.out.println("返回通知");
}
/**
* 声明最终通知,并将通知应用到指定的切入点上
* 目标类的方法执行后,执行该通知(有异常和无异常都行)
*
*/
@After(value = "cut()")
public void after(){
System.out.println("最终通知");
}
/**
* 声明异常通知,并将通知应用到指定的切入点上
* 目标类的方法在执行异常时,执行该通知
*/
@AfterThrowing(value = "cut()",throwing = "e")
public void afterThrow( Exception e ){
System.out.println("异常通知。。。异常原因:"+e.getMessage());
}
/**
* 声明环绕通知,并将通知应用到指定的切入点上
* 目标类的方法执行前后都可以通过环绕通知定义响应的处理
* 需要通过显示调用的方法,否则无法访问指定的方法 pjp.proceed()
* @param pjp
* @return
*/
@Around(value = "cut()")
public Object around(ProceedingJoinPoint pjp){
System.out.println("环绕通知-前置通知");
Object object=null;
try{
object=pjp.proceed();//要有环绕通知,就必须要执行proceed()这个方法
// System.out.println(pjp.getTarget());
System.out.println("环绕通知-返回通知");
}catch (Throwable throwable){
throwable.printStackTrace();
System.out.println("环绕通知-异常通知");
}
System.out.println("环绕通知-最终通知");
return object;
}
}
第三步:测试
public class aoptest {
public static void main(String[] args) {
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("spring.xml");
UserService userService= (UserService) applicationContext.getBean("userService");
userService.test();
}
}
通过xml实现切面
需要自己写配置文件了
<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
https://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">
<!-- 上面的命名空间xmlns和网址xsi是要按顺序一一对应的-->
<!-- 这是开启自动化扫描-->
<context:component-scan base-package="com.zks"/>
<!-- <!– 开启AOP代理–>-->
<!-- <aop:aspectj-autoproxy/>-->
<!-- <!– <context:annotation-config></context:annotation-config>–>-->
<!-- <!– <!– <bean id="roleService" class="com.zks.service.RoleService " init-method="init"/>–>–>-->
<!-- aop的相关配置-->
<aop:config>
<!-- aop切面 ref是类名,代表切面-->
<aop:aspect ref="logCut2">
<!-- aop切入点 id是方法名-->
<aop:pointcut id="cut" expression="execution(* com.zks.service..*.*(..))"/>
<!-- 配置前置通知,设置前置通知对应的方法名和切入点-->
<aop:before method="before" pointcut-ref="cut"/>
<!-- 返回通知-->
<aop:after-returning method="afterReturn" pointcut-ref="cut"/>
<!-- 异常通知-->
<aop:after-throwing method="afterThrow" pointcut-ref="cut" throwing="e"/>
<!-- 最终通知-->
<aop:after method="after" pointcut-ref="cut"/>
<!-- 环绕通知 -->
<aop:around method="around" pointcut-ref="cut"/>
</aop:aspect>
</aop:config>
</beans>
定义的切面如下:没有注解了
@Component
public class LogCut2 {
public void cut(){
}
/**
* 声明前置通知,并将通知应用到指定的切入点上
* 目标类方法执行前,执行该通知
*/
public void before(){
System.out.println("前置通知");
}
/**
* 声明返回通知,并将通知应用到指定的切入点上
* 目标类执行完后并且没有异常,执行该通知
*/
public void afterReturn(){
System.out.println("返回通知");
}
/**
* 声明最终通知,并将通知应用到指定的切入点上
* 目标类的方法执行后,执行该通知(有异常和无异常都行)
*
*/
public void after(){
System.out.println("最终通知");
}
/**
* 声明异常通知,并将通知应用到指定的切入点上
* 目标类的方法在执行异常时,执行该通知
*/
public void afterThrow( Exception e ){
System.out.println("异常通知。。。异常原因:"+e.getMessage());
}
/**
* 声明环绕通知,并将通知应用到指定的切入点上
* 目标类的方法执行前后都可以通过环绕通知定义响应的处理
* 需要通过显示调用的方法,否则无法访问指定的方法 pjp.proceed()
* @param pjp
* @return
*/
public Object around(ProceedingJoinPoint pjp){
System.out.println("环绕通知-前置通知");
Object object=null;
try{
object=pjp.proceed();//要有环绕通知,就必须要执行proceed()这个方法
// System.out.println(pjp.getTarget());
System.out.println("环绕通知-返回通知");
}catch (Throwable throwable){
throwable.printStackTrace();
System.out.println("环绕通知-异常通知");
}
System.out.println("环绕通知-最终通知");
return object;
}
}