1.切面:例如银行系统,先检测是否安全,再执行核心(业务)层,再记录日志,再清空缓存记录,除了核心层都是切面
2.通知:切面里的方法叫通知
前置通知:是在核心(业务)类前面执行的就是前置通知
后置通知:是在核心(业务)类后面执行的就是前置通知
环绕通知:
异常通知:
3.连接点:核心类(目标业务方法)就是接入点
4.织入:将目标业务方法、通知等连接起来的过程
5.代理: 代理类将所有切面写到一起
AOP
将三个jar包复制到src下的lib中,并build path - add to build path
aspectjrt.jar
aspectjweaver.jar
cglib-nodep-2.1_3.jar
在主xml中(applicationContext.xml)中写<aop>是有提示的,如果没有就是要配模板,也就是上面那个网址一样的东西。之所以<bean>有提示是因为上面配置了http://www.springframework.org/schema/beans/spring-beans-2.5.xsd
1.配置aop提示模板:
文件:spring-aop-2.5.xsd
需要主配置文件和局部配置文件的上面的链接改为:
<?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-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> </beans>
Eclipse的window - Preferences - XML Catalog - Add
将spring-aop-2.5.xsd的路径放进去,Key里放入http://www.springframework.org/schema/aop/spring-aop-2.5.xsd Ket type选第二个。ok
配置成功后输<aop就会有提示
2.配置切入点和切面
<?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-2.5.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd"> <!-- 配置安全bean --> <bean id="security" class = "cn.java.aop.Security"></bean> <!-- 配置核心业务bean --> <bean id="bankServiceImpl" class = "cn.java.aop.BankServiceImpl"></bean> <!-- 配置日志bean --> <bean id="log" class = "cn.java.aop.Log"></bean> <!-- 配置清空缓存bean --> <bean id="clean" class = "cn.java.aop.Clean"></bean> <!-- 配置aop --> <aop:config> <!-- 配置切点 .*代表这个类下的所有方法 。后面的..代表有参和无参的所有方法--> <aop:pointcut expression="execution (* cn.java.aop.BankServiceImpl.*(..))" id="abc"/> <!-- 配置切面 ref:上面需要配置切面的bean的id aop:before 代表前置通知 method:通知方法名 pointcut-ref:在哪个切入点前执行,内容为切入点的bean的id aop:after 后置通知 order:配置后置通知的执行顺序,数值越大越先执行 --> <aop:aspect ref="security"> <aop:before method="isSecurity" pointcut-ref="abc" /> </aop:aspect> <aop:aspect ref="log" order="2" > <aop:after method="record" pointcut-ref="abc" /> </aop:aspect> <aop:aspect ref="clean" order="1"> <aop:after method="qingKong" pointcut-ref="abc" /> </aop:aspect> </aop:config> </beans>
配置能接收返回值的后置通知
package cn.java.aop; public class Receive { public void printMoney(int m){ System.out.println("余额为:" + m + "元"); } }
<!-- 接受返回值,如果没有返回值就不调用 ref:要接受参数的那个类 method:类中要接受参数的那个方法 pointcut-ref:切点 returning:方法中要接收参数的那个参数 --> <aop:aspect ref="receive"> <aop:after-returning method="printMoney" pointcut-ref="abc" returning="m"/> </aop:aspect>
环绕通知
验证用户名密码
package cn.java.aop; import org.aspectj.lang.ProceedingJoinPoint; public class Auth { private String username = "wang"; private String password = "123"; public void userExist(ProceedingJoinPoint p) throws Throwable { if ("admin".equals(username) && "123".equals(password)) { //放行。继续往程序后面走 p.proceed(); }else { //没写p.proceed();就是不放行,程序不继续走 System.out.println("用户名或密码错误"); } } }
<!-- 配置环绕通知 ref:bean的id method:类中方法名 pointcut-ref:切点 --> <aop:aspect ref="auth"> <aop:around method="userExist" pointcut-ref="abc"/> </aop:aspect>
重点:ProceedingJoinPoint 是spring中的
异常通知
出错的时候不能显示给用户404 500页面,异常都捕获到一个类中
新建类名Global,方法叫handExpt()。再给这个类配置个bean
package cn.java.aop; public class Global { public void handExpt(Throwable ex) { System.out.println("出错了");//真实项目这里是要跳转到一个页面的 } }
<!-- 异常通知,当业务方法发生错误的时候才会被调用 throwing:值为接受异常的那个类中方法要接收的参数public void handExpt(Throwable ex) {System.out.println("出错了");} --> <aop:aspect ref="global"> <aop:after-throwing method="handExpt" pointcut-ref="abc" throwing="ex"/> </aop:aspect>