在之前的cglib代理原理中(至于cglib和jdk代理的区别,看之前的博文),我们涉及到了多个切面,但是那时候说的切面,还不算真正意义上的切面(没有在spring配置文件中配置)。现在我修改一个那个例子.
需求:
我们仍然查询某一个人的薪水
需求分析:
我们直接通过目标类来查询某个人的薪水,但是在我们通过调用目标方法的时候,有各种通知在运作,就像拦截器一样,如果没有相应的权限的话,就不给查询。
通知的分析:
在以前的例子中,我们用到了3个切面,分别是privilege(权限),security(安全性框架),logger(日志),当时由于我们还没有学通知的概念,所以只是调用了一下其中的方法而已,现在我们要区分一下它们对应的方法分别属于什么通知。
日志切面和安全性框架切面对于用户的权限没有要求,只要你发送了这个请求,就要经过相应的通知,所以日志和安全性框架属于前置通知。
权限切面是需要在经过了前置通知之后,然后再判断是否满足相应的条件来决定是否让客户端执行目标方法,所以权限切面的方法属于环绕通知。
代码实现:
以下是切面的定义:
//日志切面
public class Logger {
public void logging(){
System.out.println("logging");
}
}
//安全性框架切面:
public class Security {
public void security(){
System.out.println("security");
}
}
//权限切面
public class Privilege {
//设置一个变量,并且设置其getter&setter方法,这样就可以在配置文件中赋值
private String access;
/**
* 判断用户是否为admin,如果不是,就不给查询
* @param joinPoint
* @throws Throwable
*/
public void isAccess(ProceedingJoinPoint joinPoint) throws Throwable{
if("admin".equals(access)){
//允许客户端调用目标方法
joinPoint.proceed();
}else{
//抛出没有相应权限的异常
throw new RuntimeException("you have no privilege to pull this request");
}
}
//getter&setter方法,如果没有这个方法,会报错
public String getAccess() {
return access;
}
public void setAccess(String access) {
this.access = access;
}
}
//下面是目标类:
public class SalaryManager {
public void showSalary(){
System.out.println("show salary");
}
}
以下是配置文件的配置:
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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-2.5.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop-2.5.xsd">
<!--
把要用到的切面以及目标类配置到配置文件中
-->
<bean id="logger" class="cn.ansel.oneTarget2ManyAspects.Logger"></bean>
<bean id="security" class="cn.ansel.oneTarget2ManyAspects.Security"></bean>
<!--
为privilege类中的access属性赋值
-->
<bean id="privilege" class="cn.ansel.oneTarget2ManyAspects.Privilege">
<property name="access" value=""admin""></property>
</bean>
<bean id="salaryManager" class="cn.ansel.oneTarget2ManyAspects.SalaryManager"></bean>
<aop:config>
<!--
设置切入点表达式
-->
<aop:pointcut expression="execution(* cn.ansel.oneTarget2ManyAspects.SalaryManager.*(..))" id="perform"/>
<!--
有几个切面就要定义几个aop:aspect 并且把ref的值设置好
-->
<aop:aspect ref="logger">
<aop:before method="logging" pointcut-ref="perform"/>
</aop:aspect>
<aop:aspect ref="security">
<aop:before method="security" pointcut-ref="perform"/>
</aop:aspect>
<!--
在这里设置好环绕通知,
-->
<aop:aspect ref="privilege">
<aop:around method="isAccess" pointcut-ref="perform"/>
</aop:aspect>
</aop:config>
</beans>
//以下是测试类的代码:
public class testOne2Many {
@Test
public void test(){
//开启spring容器
ApplicationContext applicationContext=new ClassPathXmlApplicationContext("cn/ansel/oneTarget2ManyAspects/applicationContext.xml");
//使用cglib代理得到目标类的代理对象
SalaryManager cglibProxy=(SalaryManager) applicationContext.getBean("salaryManager");
//调用目标方法
cglibProxy.showSalary();
}
}
运行结果:
当我们把配置文件中access的值改成其他值的时候
- 1
- 1
再运行测试类:
异常: