(1)AOP是Aspect Oriented Programming的缩写,意思是面向切面编程,提供从另一个角度来考虑程序结构以完善面向对象编程(相对于OOP),即可以通过在编译期间、装载期间或运行期间实现在不修改源代码的情况下给程序动态添加功能的一种技术。通俗点说就是把可重用的功能提取出来,然后将这些通用功能在合适的时候织入到应用程序中;比如安全,日记记录,这些都是通用的功能,我们可以把它们提取出来,然后在程序执行的合适地方织入这些代码并执行它们,从而完成需要的功能并复用了这些功能。
(2)使用用户登录例子说明AOP
解释:假如现在我们在简单用户登录的逻辑上想要增加一个逻辑——通过判断登录用户的权限(管理员,普通用户等),然后使其登录到不同的页面。
原始解决方法:通过修改源代码来实现不同权限用户的登录。
if 管理员
...
else if 普通用户
...
源代码相互之间的耦合性较高,可能加一个条件判断语句也会影响其他代码,所以为了降低耦合性,AOP横空出世,可以“凌驾”于源代码之上,不用修改源代码就实现不同权限用户的登录。
AOP 底层使用动态代理 ,动态代理有两种情况
(1)切入点表达式作用:知道对哪个类里面的哪个方法进行增强
(2)语法结构: execution([权限修饰符] [返回类型] [类全路径] [方法名称]([参数列表]) )
(3)例子如下:
例 1:对 com.spring.dao.BookDao 类里面的 add 进行增强
execution(* com.spring.dao.BookDao.add(..))
例 2:对 com.spring.dao.BookDao 类里面的所有的方法进行增强
execution(* com.spring.dao.BookDao.* (..))
例 3:对 com.spring.dao 包里面所有类,类里面所有方法进行增强
execution(* com.spring.dao.*.* (..))
//被增强类
@Component //此注解的作用为创建对象
public class User {
public void add() {
System.out.println("add...... ");
}
}
@Component
public class UserProxy {
}
@Configuration //作为配置类,替代xml配置文件
@ComponentScan(basePackages = {"com.spring"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop {
}
@ComponentScan(basePackages = {“com.spring”})@EnableAspectJAutoProxy(proxyTargetClass = true)等价于xml文件中的如下配置
<context:component-scan base-package="com.spring">context:component-scan>
<aop:aspectj-autoproxy>aop:aspectj-autoproxy>
@Component
@Aspect //生成代理对象
public class UserProxy {
//前置通知
//@before注解表示作为前置通知
@Before(value = "execution(* com.spring.aop.User.add(..))")
public void before() {
System.out.println("before.....");
}
@After(value = "execution(* com.spring.aop.User.add(..))")
public void after() {
System.out.println("After.....");
}
@AfterReturning(value = "execution(* com.spring.aop.User.add(..))")
public void afterReturning() {
System.out.println("AfterReturning.....");
}
@AfterThrowing(value = "execution(* com.spring.aop.User.add(..))")
public void afterThrowing() {
System.out.println("AfterThrowing.....");
}
@Around(value = "execution(* com.spring.aop.User.add(..))")
public void around(ProceedingJoinPoint proceedingJoinPoint) {
System.out.println("环绕之前....");
try {
proceedingJoinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕之后....");
}
}
public class TestAop {
@Test
public void testAop() {
ApplicationContext context = new AnnotationConfigApplicationContext(ConfigAop.class);
User user = context.getBean("user", User.class);
user.add();
}
@Component
@Aspect //生成代理对象
public class UserProxy {
//相同切入点抽取
@Pointcut(value = "execution(* com.spring.aop.User.add(..))")
public void point() {
}
//前置通知
//@before注解表示作为前置通知
@Before(value = "point()")
public void before() {
System.out.println("before.....");
}
@After(value = "point()")
public void after() {
System.out.println("After.....");
}
@AfterReturning(value = "point()")
public void afterReturning() {
System.out.println("AfterReturning.....");
}
@AfterThrowing(value = "point()")
public void afterThrowing() {
System.out.println("AfterThrowing.....");
}
@Around(value = "point()")
public void around(ProceedingJoinPoint proceedingJoinPoint) {
System.out.println("环绕之前....");
try {
proceedingJoinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕之后....");
}
}
当有多个增强类对一个方法进行增强时,需要设置增强类的优先级。
通过@Order(数字类型)注解实现,数字越小,优先级越高
//增强类1
@Component
@Aspect //生成代理对象
@Order(3)
public class UserProxy {
//相同切入点抽取
@Pointcut(value = "execution(* com.spring.aop.User.add(..))")
public void point() {
}
//前置通知
//@before注解表示作为前置通知
@Before(value = "point()")
public void before() {
System.out.println("before.....");
}
@After(value = "point()")
public void after() {
System.out.println("After.....");
}
@AfterReturning(value = "point()")
public void afterReturning() {
System.out.println("AfterReturning.....");
}
@AfterThrowing(value = "point()")
public void afterThrowing() {
System.out.println("AfterThrowing.....");
}
@Around(value = "point()")
public void around(ProceedingJoinPoint proceedingJoinPoint) {
System.out.println("环绕之前....");
try {
proceedingJoinPoint.proceed();
} catch (Throwable e) {
e.printStackTrace();
}
System.out.println("环绕之后....");
}
}
//增强类2
@Component
@Aspect
@Order(1) //数字越小,优先级越高
public class PersonProxy {
@Pointcut(value = "execution(* com.spring.aop.User.add(..))")
public void point() {
}
@Before(value = "point()")
public void before() {
System.out.println("增强类2的before...");
}
}
<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.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
<bean id="user" class="com.spring.aop.User">bean>
<bean id="userProxy" class="com.spring.aop.UserProxy">bean>
<aop:config>
<aop:pointcut id="p" expression="execution(* com.spring.aop.User.add(..))"/>
<aop:aspect ref="userProxy">
<aop:before method="before" pointcut-ref="p">aop:before>
aop:aspect>
aop:config>
beans>
跟上面的基于注解的通知效果是一样的
//测试类
@Test
public void testAop() {
ClassPathXmlApplicationContext context =
new ClassPathXmlApplicationContext("bean1.xml");
User user = context.getBean("user", User.class);
user.add();
}