一、AOP的概述
AOP是基于反射与动态代理的实现,java有反射的中间层,让AOP的实现更加简单,而C++想实现相比会较为困难。
AOP为:(aspect oriented programming),面向切面编程。是对OOP的补充,弥补OOP的不足。
作用:在不修改源码的前提下,给项目增加新的公共功能,如:权限,日志,事务(数据库中同时成功或同时失败的操作的集合)。
二、AOP的组成要数
分别有以下几点:
- advice:通知。即新增的功能。比如写日志。
- target:目标。通知加入的目标类。
- joinpoint:切点。通知加入的目标类的具体位置。
- pointcut:切线。所有切点的集合。
- aspect:切面。切线+通知。
- weaving:动词。织入。
- introduction:在不修改代码的前提下,引入可以在运行期为类动态地添加一些方法或字段。
三、AOP原理
基于设计模式之“代理模式”。agent/proxy。
代码实现上面分为:静态代理 和 动态代理。
代理模式的原理:代理对象和被代理对象实现同样的业务接口,由代理对象代替其
完成业务行为,并增加“附加行为”。
例如:我想去动物园买票,传统方式是直接到动物园门口购票。而现在我可以找个人代替我买票,那个人就是代理人,而他也要向我索取金钱(成本+代理费。。)之类的附加行为,就是代理业务。
而现在的AOP就是那个代理人,替我们去做事的代理人。
注意:spring实现aop采用的”动态代理”的方式。动态代理意思是,去帮你做事的代理对象不是固定的,是用Spring动态创建的。
四、Spring对AOP的支持
Spring中AOP代理由Spring的IOC容器负责生成、管理,其依赖关系也由IOC容器负责管理。因此,AOP代理可以直接使用容器中的其它bean实例作为目标,这种关系可由IOC容器的依赖注入提供。
AOP通知日志的简单实例,创建一个User接口,具有登陆与注册两个方法:
public interface User {
void login();
void register();
}
创建一个代理对象UserImpl,实现User接口:
public class UserImpl implements User {
private String role;
public String getRole() {
return role;
}
public void setRole(String role) {
this.role = role;
}
@Override
public void login() {
System.out.println("完成登录的业务方法!");
}
@Override
public void register() {
System.out.println("完成注册的业务方法!");
}
}
创建一个通知类对象MyAdvice:
public class MyAdvice {
public void beforelog()
{
System.out.println("这是前置通知的日志。");
}
public void afterlog()
{
System.out.println("这是后置通知的日志。");
}
public void aroundlog(ProceedingJoinPoint p) throws Throwable
{
System.out.println("环绕前的日志!");
p.proceed(); //让原来的业务方法执行!
System.out.println("环绕后的日志!");
}
public void throwlog()
{
System.out.println("这是异常通知的日志");
}
}
在applicationContext.xml文件配置头部:
<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-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
接着配置其代理对象,和通知类对象及织入关系
<!-- 创建1个业务实现类对象 -->
<bean id="user" class="com.sunsharing.entity.UserImpl">
</bean>
<!--创建1个自定义通知类对象 -->
<bean id="myadvice" class="com.sunsharing.entity.MyAdvice">
</bean>
<!-- 配置 织入关系 -->
<aop:config>
<!-- 定义1条切线 -->
<aop:pointcut expression="execution(* com.sunsharing.entity.UserImpl.login(..))" id="mypc"/> <!--这里监听的是login方法-->
<!--配置切面 ,引用自定义通知对象-->
<aop:aspect ref="myadvice">
<aop:before method="beforelog" pointcut-ref="mypc"/>
<aop:after method="afterlog" pointcut-ref="mypc"/>
<aop:around method="aroundlog" pointcut-ref="mypc"/>
<aop:after-throwing method="throwlog" pointcut-ref="mypc"/>
</aop:aspect>
</aop:config>
最后,在TestUser测试类中进行日志测试:
import com.sunsharing.entity.User;
import org.springframework.beans.factory.BeanFactory;
import org.springframework.context.support.ClassPathXmlApplicationContext;
public class TestUser {
@org.junit.Test
public void test() {
BeanFactory fac = new ClassPathXmlApplicationContext("applicationContext.xml");
User user = (User) fac.getBean("user");
user.login();
}
}
输出结果:
其中还有个抛出异常的日志监听,在register方法抛出个自定义异常试试。
@Override
public void register() {
throw new RuntimeException("这是注册的异常!");
//System.out.println("完成注册的业务方法!");
}
然后把applicationContext中的监听方法改为rigister
<aop:pointcut expression="execution(* com.sunsharing.entity.UserImpl.register(..))" id="mypc"/>
测试类中运行后,输出的结果为:
以上是日志功能的实现,接下来再讲个权限功能的实现
五、AOP的权限功能
沿用以上的例子,加个周四无法注册的权限控制。
创建一个MyRegAdvice的自定义通知类:
package com.sunsharing.entity;
import java.util.Calendar;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyRegAdvice
{
//这是环绕通知
public void checkday(ProceedingJoinPoint p) throws Throwable
{
Calendar c = Calendar.getInstance();
int day = c.get(Calendar.DAY_OF_WEEK);
if(day==5)//周日是第一天为1,因此周四是5,亲测!
{
System.out.println("周四无法注册!");
return;
}
p.proceed(); //其他情况,允许往前走。
}
}
创建一个applicationContext_register.xml配置文件:
<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-3.0.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop-3.0.xsd">
<!-- 创建1个业务实现类对象 -->
<bean id="user" class="com.sunsharing.entity.UserImpl">
</bean>
<!--创建1个自定义通知类对象 -->
<bean id="myadvice" class="com.sunsharing.entity.MyRegAdvice">
</bean>
<!-- 配置 织入关系 -->
<aop:config>
<!-- 定义1条切线 -->
<aop:pointcut expression="execution(* com.sunsharing.entity.UserImpl.reg*(..))" id="mypc"/>
<!--配置切面 ,引用自定义通知对象-->
<aop:aspect ref="myadvice">
<aop:around method="checkday" pointcut-ref="mypc"/>
</aop:aspect>
</aop:config>
</beans>
最后在测试类进行测试,测试类完全不用改动。
输出结果为:
本文详细介绍了Spring的AOP编程,包括AOP的概述、组成要素、原理,以及Spring对AOP的支持。通过实例展示了如何使用AOP进行日志记录和权限控制,强调了AOP在不修改源码前提下增强功能的能力。

1399

被折叠的 条评论
为什么被折叠?



