注意,我们在执行业务的时候必须先执行isSecurity()方法,然后再执行业务中的那三个方法。然后执行log以及clearResource方法。要实现上述操作流程,可以创建一个BankServiceProxy类将其他几个模块进行合包(这里将其他几个类看为几个不同的模块),再创建一个Window类进行调用。看上图,除了第二行之外,其他几个称之为切面,切面中的方法称之为通知,Security、Clean、RiZhi都为切面。
2. 通知:切面中的方法为通知
a) 前置通知:在目标方法之前执行的方法
b) 后置通知:在目标方法之后执行的方法
c) 环绕通知
d) 异常通知
3. 连接点:目标方法
4. 织入:将目标方法、通知等连接起来的过程
代码如下:
package cn.java.java.aop2;
public class Window {
public static void main(String[] args) {
BankServiceProxy bsP=new BankServiceProxy();
bsP.chaMoney();//调用查询的方法
}
}
package cn.java.java.aop2;
/**
* 代理类
* @author 26326
*
*/
public class BankServiceProxy {
private BankServiceImpl bsi=new BankServiceImpl();
private Security s=new Security();
private RiZhi rz=new RiZhi();
private Clean c=new Clean();
public void chaMoney() {
s.isSecurity();
bsi.getMoney();
rz.log();
c.clearResource();
}
public void moneyZhuan() {
s.isSecurity();
bsi.zhuanMoney();
rz.log();
c.clearResource();
}
public void moneyInvest() {
s.isSecurity();
bsi.invest();
rz.log();
c.clearResource();
}
}
package cn.java.java.aop2;
/**
* 清空数据
* @author 26326
*
*/
public class Clean {
public void clearResource() {
System.out.println("RiZhi........clearResource()........数据已经清空");
}
}
package cn.java.java.aop2;
/**
* 日志
* @author 26326
*
*/
public class RiZhi {
public void log() {
System.out.println("RiZhi........log()........记录日志");
}
}
package cn.java.java.aop2;
/**
* 环境监测
* @author 26326
*
*/
public class Security {
public void isSecurity() {
System.out.println("Security........isSecurity()........");
}
}
package cn.java.java.aop2;
public class BankServiceImpl {
/**
* 查询余额
*/
public void getMoney() {
System.out.println("BankServiceImpl........getMoney()........余额为500万");
}
/**
* 转账
*/
public void zhuanMoney() {
System.out.println("BankServiceImpl........zhuanMoney()........转账100万");
}
/**
* 投资理财
*/
public void invest() {
System.out.println("BankServiceImpl........invest()........投资成功");
}
}
接下来,我们可以通过配置来实现。这里用的是自己创建的一个aop.xml的局部配置文件,然后还要在applicationContext中进行关联,
同时,项目中必须有如下的jar包:
还要进行如下的配置,注意在局部配置文件中也做如下的配置,这样在写<aop>标签时就会有提示。
将http://www.springframework.org/schema/aop/spring-aop-2.5.xsd放入key中,location是在本地中的
这个文件的位置,
这样就配置完毕。
然后在aop配置文件中对切面进行配置,如果以后不需要这个功能了,可以在配置文件直接删除对它的配置。
下面是相关代码:
这是aop.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-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.java.aop2.Security"></bean>
<!-- 配置核心业务bean-->
<bean id="bankServiceImpl" class="cn.java.java.aop2.BankServiceImpl"></bean>
<!-- 配置日志bean-->
<bean id="riZhi" class="cn.java.java.aop2.RiZhi"></bean>
<!-- 配置清空数据bean-->
<bean id="clean" class="cn.java.java.aop2.Clean"></bean>
<!-- 配置aop -->
<aop:config >
<!-- 首先配置切入点,id可随便写,cn.java.java.aop2.BankServiceImpl.*:表示BankServiceImpl类中的所有方法都是切入点
<aop:pointcut expression="cn.java.java.aop2.BankServiceImpl.*" id="aaa"/>,这个不常用
下面的表示将cn.java.java.aop2.BankServiceImpl中的所有方法作为切入点,这个方法可能带参数也可能不带参数
-->
<aop:pointcut expression="execution (* cn.java.java.aop2.BankServiceImpl.* (..))" id="aaa"/>
<!-- 然后配置切面 (切面中的方法称之为通知),注意:ref中的值和bean中的id值一致-->
<aop:aspect ref="security">
<!-- aop:before 代表前置通知,在执行这个类的方法的时候会先执行这个方法
method 通知方法名,
pointcut-ref 切入点id
-->
<aop:before method="isSecurity" pointcut-ref="aaa"/>
</aop:aspect>
<!-- 配置日志切面,order数值越大越先执行 -->
<aop:aspect ref="riZhi" order="2">
<aop:after method="Log" pointcut-ref="aaa"/>
</aop:aspect>
<!-- 配置清空数据切面 -->
<aop:aspect ref="clean" order="1">
<aop:after method="clearResource" pointcut-ref="aaa"/>
</aop:aspect>
</aop:config>
</beans>
<?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">
<import resource="cn/java/di/jvbu.xml"/>
</beans>
package cn.java.java.aop2;
/**
* 环境监测
* @author 26326
*
*/
public class Security {
public void isSecurity() {
System.out.println("Security........isSecurity()........");
}
}
package cn.java.java.aop2;
/**
* 日志
* @author 26326
*
*/
public class RiZhi {
public void log() {
System.out.println("RiZhi........log()........记录日志");
}
}
package cn.java.java.aop2;
/**
* 清空数据
* @author 26326
*
*/
public class Clean {
public void clearResource() {
System.out.println("RiZhi........clearResource()........数据已经清空");
}
}
package cn.java.java.aop2;
public class BankServiceImpl {
/**
* 查询余额
*/
public void getMoney() {
System.out.println("BankServiceImpl........getMoney()........余额为500万");
}
/**
* 转账
*/
public void zhuanMoney() {
System.out.println("BankServiceImpl........zhuanMoney()........转账100万");
}
/**
* 投资理财
*/
public void invest() {
System.out.println("BankServiceImpl........invest()........投资成功");
}
}
在window类中进行调用结果如下:
三 带返回值的后置通知
现在希望业务中的那三个功能都能返回结果,并且都能被后面的切面receive接收到,注意只接收有参数的,否则就不会调用receive方法。
receive类:
package cn.java.java.aop2;
/**
* 用来接收目标方法返回值的切面
* @author 26326
*
*/
public class Receive {
public void printMoney(Object m) {//这里为object类型,可以解决调用的方法中与这里接收的信息类型不匹配的问题
System.out.println("当前余额为:"+m);
}
}
接下来是在aop中的配置:
<?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.java.aop2.Security"></bean>
<!-- 配置核心业务bean-->
<bean id="bankServiceImpl" class="cn.java.java.aop2.BankServiceImpl"></bean>
<!-- 配置日志bean-->
<bean id="riZhi" class="cn.java.java.aop2.RiZhi"></bean>
<!-- 配置清空数据bean-->
<bean id="clean" class="cn.java.java.aop2.Clean"></bean>
<!-- 配置接收返回值的切面 -->
<bean id="receive" class="cn.java.java.aop2.Receive"></bean>
<!-- 配置aop -->
<aop:config >
<!-- 首先配置切入点,id可随便写,cn.java.java.aop2.BankServiceImpl.*:表示BankServiceImpl类中的所有方法都是切入点
<aop:pointcut expression="cn.java.java.aop2.BankServiceImpl.*" id="aaa"/>,这个不常用
下面的表示将cn.java.java.aop2.BankServiceImpl中的所有方法作为切入点,这个方法可能带参数也可能不带参数
-->
<aop:pointcut expression="execution (* cn.java.java.aop2.BankServiceImpl.* (..))" id="aaa"/>
<!-- 然后配置切面 (切面中的方法称之为通知),注意:ref中的值和bean中的id值一致-->
<aop:aspect ref="security">
<!-- aop:before 代表前置通知,在执行这个类的方法的时候会先执行这个方法
method 通知方法名,
pointcut-ref 切入点id
-->
<aop:before method="isSecurity" pointcut-ref="aaa"/>
</aop:aspect>
<!-- 配置日志切面,order数值越大越先执行 -->
<aop:aspect ref="riZhi" order="2">
<aop:after method="Log" pointcut-ref="aaa"/>
</aop:aspect>
<!-- 配置清空数据切面 -->
<aop:aspect ref="clean" order="1">
<aop:after method="clearResource" pointcut-ref="aaa"/>
</aop:aspect>
<!-- 配置接收参数的切面 -->
<aop:aspect ref="receive">
<aop:after-returning method="printMoney" pointcut-ref="aaa" returning="m"/>
</aop:aspect>
</aop:config>
</beans>
下图是结果:
四 环绕通知
只有满足条件的时候,后面的前置通知与后置通知才能去执行。
创建Auth类:
package cn.java.java.aop2;
import org.aspectj.lang.ProceedingJoinPoint;
/**
* 验证用户名与密码是否正确的切面
* @author 26326
*
*/
public class Auth {
private String username="admin";
private String password="123";
//ProceedingJoinPoint是spring框架传递来的
public void isUserExist(ProceedingJoinPoint pp) throws Throwable{
if("admin".equals(username)&&"123".equals(password)) {
//放行
pp.proceed();
}else {
//用户名或者密码错误
System.out.println("登录错误");
}
}
}
<?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.java.aop2.Security"></bean>
<!-- 配置核心业务bean-->
<bean id="bankServiceImpl" class="cn.java.java.aop2.BankServiceImpl"></bean>
<!-- 配置日志bean-->
<bean id="riZhi" class="cn.java.java.aop2.RiZhi"></bean>
<!-- 配置清空数据bean-->
<bean id="clean" class="cn.java.java.aop2.Clean"></bean>
<!-- 配置接收返回值的切面 -->
<bean id="receive" class="cn.java.java.aop2.Receive"></bean>
<!-- 配置验证用户姓名与密码的切面 -->
<bean id="auth" class="cn.java.java.aop2.Auth"></bean>
<!-- 配置aop -->
<aop:config >
<!-- 首先配置切入点,id可随便写,cn.java.java.aop2.BankServiceImpl.*:表示BankServiceImpl类中的所有方法都是切入点
<aop:pointcut expression="cn.java.java.aop2.BankServiceImpl.*" id="aaa"/>,这个不常用
下面的表示将cn.java.java.aop2.BankServiceImpl中的所有方法作为切入点,这个方法可能带参数也可能不带参数
-->
<aop:pointcut expression="execution (* cn.java.java.aop2.BankServiceImpl.* (..))" id="aaa"/>
<!-- 配置验证用户姓名与密码的环绕通知的切面 -->
<aop:aspect ref="auth">
<aop:around method="isUserExist" pointcut-ref="aaa" />
</aop:aspect>
<!-- 然后配置切面 (切面中的方法称之为通知),注意:ref中的值和bean中的id值一致-->
<aop:aspect ref="security">
<!-- aop:before 代表前置通知,在执行这个类的方法的时候会先执行这个方法
method 通知方法名,
pointcut-ref 切入点id
-->
<aop:before method="isSecurity" pointcut-ref="aaa"/>
</aop:aspect>
<!-- 配置日志切面,order数值越大越先执行 -->
<aop:aspect ref="riZhi" order="2">
<aop:after method="Log" pointcut-ref="aaa"/>
</aop:aspect>
<!-- 配置清空数据切面 -->
<aop:aspect ref="clean" order="1">
<aop:after method="clearResource" pointcut-ref="aaa"/>
</aop:aspect>
<!-- 配置接收参数的切面 -->
<aop:aspect ref="receive">
<aop:after-returning method="printMoney" pointcut-ref="aaa" returning="m"/>
</aop:aspect>
</aop:config>
</beans>