三、Aspectj能做什么
clean modularization of crosscutting concerns, such as error checking and handling, synchronization, context-sensitive behavior, performance optimizations, monitoring and logging, debugging support, and multi-object protocols。
大意是说:干净的模块化横切关注点(也就是说单纯,基本上无侵入),如错误检查和处理,同步,上下文敏感的行为,性能优化,监控和记录,调试支持,多目标的协议。
四、还有那些常用的Aop,以及他们的区别
Jboss Aop:我基本上没有用过,所以没有发言权
Spring Aop:Spring自己原生的Aop,只能用一个词来形容:难用。 你需要实现大量的接口,继承大量的类,所以spring aop一度被千夫所指。这于他的无侵入,低耦合完全冲突。不过Spring对开源的优秀框架,组建向来是采用兼容,并入的态度。所以,后来的Spring 就提供了Aspectj支持,也就是我们后来所说的基于纯POJO的Aop。
区别:Spring Aop采用的动态织入,而Aspectj是静态织入。静态织入:指在编译时期就织入,即:编译出来的class文件,字节码就已经被织入了。动态织入又分静动两种,静则指织入过程只在第一次调用时执行;动则指根据代码动态运行的中间状态来决定如何操作,每次调用Target的时候都执行。有不清楚的同学,可以自己补下基础的代理知识。
https://blog.youkuaiyun.com/qq_15037231/article/details/78749581上面是转的,原地址在这。
spring支持AspectJ的开发,所以我们是用的AspectJ是在spring容器里进行的。
AspectJ开发:通过配置文件方式
新建java项目
导包
ps:前两个包没有spring开头是因为这是spring买的人家的
这是我的项目结构
首先创建一个Person类
package com.cbb.bean;
/**
* 类描述:一个人的类
* 作者: 地铁与人海
* 创建日期:2019年3月13日
* 修改人:
* 修改日期:
* 修改内容:
* 版本号: 1.0.0
*/
public class Person {
public void eat() {
System.err.println("吃饭......");
}
public void run() {
System.err.println("跑步......");
}
}
我们为了实现异常通知,在Person类里加了个方法
public String run(String name) {
System.err.println(name+"跑步......");
//int a = 1/0;
return name;
再创建一个通知类,写通知的类,作为系统层次的服务(模拟日志之类的东西)
我将五种通知都写在上面了,其中环绕通知和其他的通知不一样
package com.cbb.advice;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* 类描述:通知类,做系统服务的类
* 作者: 地铁与人海
* 创建日期:2019年3月13日
* 修改人:
* 修改日期:
* 修改内容:
* 版本号: 1.0.0
*/
public class MyAdvice {
public void doBefore() {
System.err.println("前通知...");
}
public void doAfter() {
System.err.println("后通知...");
}
public void afterR() {
System.err.println("返回后通知...");
}
public void throwing() {
System.err.println("异常通知...");
}
/**
* 方法描述:环绕通知的写法
* @param joinPoint 连接点
* @throws Throwable
*/
public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {
System.err.println("环绕通知开始......");
Object obj = joinPoint.proceed();
System.err.println("环绕通知结束......");
return obj;
}
}
然后我们写注解,建一个applicationContext.xml文件(名字其实一直都可以随便起)
必须要有的如图:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
</beans>
我们就在<beans>
标签里面进行注解开发。
首先把类配置到这里面
<!-- 只增强一个,不用注解的方式 -->
<!-- 待被增强的类,先放到这来 -->
<bean id = "person" class="com.cbb.bean.Person"></bean>
<!-- 配置一个切面 -->
我们要实现的,是在使用person类的时候,添加通知类的通知进去(也就是调用方法),我们进行配置,就是配置切面(也是一个bean)和切点。
切面是所有通知,切点是要被增强的类和方法
明确之后,我们写test类
package com.cbb.test;
import org.junit.Test;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.cbb.bean.Person;
import com.cbb.service.SomeService;
/**
* 类描述:
* 作者: 地铁与人海
* 创建日期:2019年3月13日
* 修改人:
* 修改日期:
* 修改内容:
* 版本号: 1.0.0
*/
public class AOPTest {
@Test
public void test() {
ApplicationContext app =
new ClassPathXmlApplicationContext("applicationContext.xml");
Person p = app.getBean(Person.class);
p.run("jack");
}
}
就是new类,调用方法而已。现在不会有任何通知,因为我们还没有配置。
我们开始配置,先配置一个切面
<!-- 配置一个切面 -->
<bean id = "myAdvice" class="com.cbb.advice.MyAdvice"></bean>
其实就是把这个类也由bean进行管理
现在正是进行aop配置
配置切面。
<!-- aop配置 -->
<aop:config>
<!-- 配置切面 要通过ref指向做增强的bean前面-->
<aop:aspect ref="myAdvice">
</aop:aspect>
</aop:config>
在里面要配置两个东西,切点和通知
配置切点
<!--配置切点 可以放到切面里面,代表只有本切面可以使用这个切点,也可以放到切面外部,代表全局,所有的切面都可以使用这个切点
expression:写切点表达式:写切点要使用到哪个地方去。
起个id,别的地方就可以调用了
-->
<aop:pointcut expression="execution(* com.cbb.*.*(..))" id="myCut"/>
我们将它放在切面里面
<!-- aop配置 -->
<aop:config>
<!-- 配置切面 要通过ref指向做增强的bean前面-->
<aop:aspect ref="myAdvice">
<!--配置切点 可以放到切面里面,代表只有本切面可以使用这个切点,也可以放到切面外部,代表全局,所有的切面都可以使用这个切点
expression:写切点表达式:写切点要使用到哪个地方去。
-->
<aop:pointcut expression="execution(* com.cbb..*.*(..))" id="myCut"/>
</aop:aspect>
</aop:config>
然后我们进行配置通知,让myAdvice里面的各个方法声明为各种通知
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
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">
<!-- 只增强一个,不用注解的方式 -->
<!-- 待被增强的类,先放到这来 -->
<bean id = "person" class="com.cbb.bean.Person"></bean>
<!-- 配置一个切面 -->
<bean id = "myAdvice" class="com.cbb.advice.MyAdvice"></bean>
<!-- aop配置 -->
<aop:config>
<!-- 配置切面 要通过ref指向做增强的bean前面-->
<aop:aspect ref="myAdvice">
<!--配置切点 可以放到切面里面,代表只有本切面可以使用这个切点,也可以放到切面外部,代表全局,所有的切面都可以使用这个切点
expression:写切点表达式:写切点要使用到哪个地方去。
-->
<aop:pointcut expression="execution(* com.cbb..*.*(..))" id="myCut"/>
<!-- 配置前通知 method:对应切面的哪个方法 pointcut-ref:对应得切点-->
<aop:before method="doBefore" pointcut-ref="myCut"/>
<aop:before method="doBefore" pointcut-ref="myCut"/><!-- 可以重复· -->
<!-- 后通知 :可以称为最终通知,无论如何都会执行的-->
<aop:after method="doAfter" pointcut-ref="myCut"/>
<!-- 返回后通知 :只有正常返回才会执行-->
<aop:after-returning method="afterR" pointcut-ref="myCut"/>
<!-- 异常通知:只有异常抛出才会执行-->
<aop:after-throwing method="throwing" pointcut-ref="myCut"/>
<!-- 环绕通知: = 前通知+返回后通知 在待增强的方法执行的前后执行 -->
<aop:around method="doAround" pointcut-ref="myCut"/>
</aop:aspect>
</aop:config>
</beans>
然后我们就可以实现了
切点表达式
切点表达式的解释
我们通过参数的个数和类型进行区分方法,是因为会有重载方法
切点表达式功能:
- 1.可以控制返回参数类型
- 2.控制参数
- 3.控制类的深度(根据控制包,来控制深度)
- 4.面向接口的(你切的接口方法,则此接口的实现类也会被切)
符号(通配符)功能
符号 | 功能 |
---|---|
* | 在返回值上,代表任意类型。在路径上,代表任意类或者是方法 |
两个点(破编辑器,打不出来,自动变成三个点了,参考上面吧) | 任意多个。0~N个 |
注意点:
execution(* com.cbb. * . *(..))
对com.cbb包下的所有类切,但是对子包下的类无效
execution(* com.cbb.. * . *(..))
对com.cbb包下 和 子包下的所有类切
就是.和*的区别,注意。
最好使用下面那个,简洁大方,宁杀错不放过。
还有两种开发方式,我现在不讲,因为没时间了,我需要把老师最近讲的内容也整理到csdn上,有需要的童鞋可以把邮箱留下,我给把课件发过去。
END