AOP(aspect oriented programming)面向切面编程
1.aop概述
aop简写aspect oriented programming,中文名字:面向切面编程;通过预编译方式和运行期动态代理实现程序功能的维护的一种技术,aop是oop的延续,aop是一个概念,并没有设定具体语言的实现,它能客服那些值有单继承特性语言的缺点.主要功能是日志记录,性能统计,安全控制,事务处理,异常处理等等.oop针对业务过程的实体及行为进行抽取封装,以获取更加清晰高效的逻辑单元划分.aop则是针对业务处理过程中的切面进行提取,它所面对的是处理过程中的某个步骤或阶段已获得逻辑过程中个部分之间低耦合的隔离效果.这两种设计思想在目标上有本质的差异.ood/oop面向名领域,aop面向动词领域
2.aop相关术语
| 1.目标对象(target) | 被代理的类(被增强的类) |
| 2.连接点(join point) | 那些被拦截到的点,在spring中这些点指的是方法,因为spring只支持方法类型的连接点. |
| 3.切入点(pointcut) |
表示一组连接点,这些连接点通过逻辑关系组合起来,或是通过通配,正则表达式等方式集中起来,它定义了项应的advice将要发生的地方 我们对那些哪些方法进行拦截的定义. |
| 4.通知(advice) |
拦截到方法之后所要做的事情,通知分为前置通知,后置通知,异常通知,最终通知,环绕通知, advice定义了在pointcut里面定义的程序点具体要做的操作 |
| 5.引介(introduction) | 引介是一种特殊的通知,在不修改类代码的前提下,introduction可以在运行期为类动态地添加一些属性或方法 |
| 6.切面(aspect) | 是切入点和通知的结合 |
| 7.织入(weaving) |
是一个过程,是将切面应用到目标对象从而创建出aop代理对象的过程,织入可以在编译期,类的加载期,运行期进行. spring采用的动态织入,而aspectj采用的织入方式为静态. |
| 8.代理(proxy) | 一个类被aop织入增强后,就会产生一个结果代理类 |
3.aop的底层实现,
aop分为静态aop和动态aop
静态aop:是将切面代码直接编译到java类中(espectj框架)
动态aop:是将切面代码织入实现aop(JDK和cglib),织入只是一个过程(编译时期,类加载时期,运行时期),这个过程一般在运行时期,
3.1 jdk代理工厂 (ProxyFactory)

1 public class ProxyFactory implements InvocationHandler{
2 private Object target;
3
4 public ProxyFactory(Object target) {
5 super();
6 this.target = target;
7 }
8 /*//创建代理对象 为了代理工厂的可扩展性 所以返回值为object 实现方法一
9 public Object createProxyFactory(){
10 Object object = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),new ProxyClass(target));
11 return object;
12 }*/
13 //实现方法二
14 public Object createProxyFactory(){
15 Object object = Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),this);
16 return object;
17 }
18 @Override
19 public Object invoke(Object proxy, Method method, Object[] args)
20 throws Throwable {
21 System.out.println("rizhi");
22 return method.invoke(target, args);
23 }
24 }
IUserService接口

public interface IUserService {
public abstract void login();
}
UserServiceImp类(IUserService的实现类)

public class UserServiceImp implements IUserService{
@Override
public void login() {
System.out.println("login....method...");
}
}
ProxyClass(实现方法一)

public class ProxyClass implements InvocationHandler {
private Object target;
public ProxtClass(Object target) {
this.target=target;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
System.out.println("日志文件");
Object invoke = method.invoke(target, args);
return invoke;
}
}
测试方法

@Test
public void test01(){
IUserService iUserService=new UserServiceImp();
ProxyFactory proxyFactory=new ProxyFactory(iUserService);
IUserService ius = (IUserService) proxyFactory.createProxyFactory();
ius.login();
}
3.2 cglib代理工厂

public class ProxyFactory implements MethodInterceptor{
private Object target;
public ProxyFactory(Object target) {
super();
this.target = target;
}
public Object createProxyFactory(){
//创建enhancer
Enhancer enhancer=new Enhancer();
//创建目标对象
enhancer.setSuperclass(target.getClass());
//设置回调操作
enhancer.setCallback(this);
return enhancer.create();
}
@Override
public Object intercept(Object arg0, Method method, Object[] arg2,
MethodProxy arg3) throws Throwable {
System.out.println("日志cglib");
return method.invoke(target, arg2);
}
}
4.spring aop传统编程
包结构:

IUserService接口

public interface IUserService {
public abstract void login();
public abstract void add();
public abstract void del();
}
UserServiceImp实现类

public class UserServiceImp implements IUserService{
@Override
public void login() {
System.out.println("login....method...");
}
@Override
public void add() {
System.out.println("add");
}
@Override
public void del() {
System.out.println("del");
}
}
UserHelp类

public class UserHelp implements MethodBeforeAdvice,AfterReturningAdvice,org.aopalliance.intercept.MethodInterceptor{
@Override
public void before(Method arg0, Object[] arg1, Object arg2)
throws Throwable {
System.out.println("前置通知");
}
@Override
public void afterReturning(Object arg0, Method arg1, Object[] arg2,
Object arg3) throws Throwable {
System.out.println("后置通知");
}
@Override
public Object invoke(MethodInvocation mi) throws Throwable {
System.out.println("环绕前");
Object proceed = mi.proceed();
System.out.println("环绕后");
return proceed;
}
}
applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--定义目标类target -->
<bean id="userService" class="com.baidu.aop.demo.UserServiceImp"></bean>
<!-- 通知advice -->
<bean id="userServiceadvice" class="com.baidu.aop.demo.UserHelp"></bean>
<!-- 切点 pointcut-->
<bean id="userServicePointcut" class="org.springframework.aop.support.NameMatchMethodPointcut">
<property name="mappedNames">
<list>
<value>add</value>
<value>login</value>
</list>
</property>
</bean>
<!-- 切面 advice+pointcut-->
<bean id="userServiceAspect" class="org.springframework.aop.support.DefaultPointcutAdvisor">
<property name="advice" ref="userServiceadvice"></property>
<property name="pointcut" ref="userServicePointcut"></property>
</bean>
<!-- 代理 -->
<bean id="userServiceProxy" class="org.springframework.aop.framework.ProxyFactoryBean">
<property name="target" ref="userService"></property>
<property name="interceptorNames" value="userServiceAspect"></property>
<property name="proxyInterfaces" value="com.baidu.aop.demo.IUserService"></property>
</bean>
<!-- <import resource="./aop1.xml"/> -->
</beans>
测试类

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class AopTest {
@Autowired
@Qualifier("userServiceProxy")
private IUserService userService;
@Test
public void test01(){
userService.login();
System.out.println("------------");
userService.add();
System.out.println("-----------");
userService.del();
}
}
测试结果:

环绕前 前置通知 login....method... 后置通知 环绕后 ------------ 环绕前 前置通知 add 后置通知 环绕后 ----------- del
基于aspectj切面传统开发

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--定义目标类target -->
<bean id="userService" class="com.baidu.aop.demo.UserServiceImp"></bean>
<!-- 通知advice -->
<bean id="userServiceadvice" class="com.baidu.aop.demo.UserHelp"></bean>
<!-- 切面你与切点的声明 -->
<aop:config>
<!-- 定义切点 -->
<aop:pointcut expression="execution(* com.baidu.aop.demo.IUserService.*(..))" id="userServicePointcut"/>
<!--定义切面-->
<aop:advisor advice-ref="userServiceadvice" pointcut-ref="userServicePointcut"/>
</aop:config>
</beans>
测试类

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class AopTest {
@Autowired
//@Qualifier("userServiceProxy")注释掉
private IUserService userService;
@Test
public void test01(){
userService.login();
System.out.println("------------");
userService.add();
System.out.println("-----------");
userService.del();
}
}
5.spring 整合aspectj框架实现aop
applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!--定义目标类target -->
<bean id="userService" class="com.baidu.aop.spring_aspectj.UserServiceImp"></bean>
<!-- 通知advice -->
<bean id="userServiceadvice" class="com.baidu.aop.spring_aspectj.UserHelp"></bean>
<!-- 切面你与切点的声明 -->
<aop:config>
<!-- 定义切点 -->
<aop:pointcut expression="execution(* com.baidu.aop.spring_aspectj.IUserService.*(..))" id="userServicePointcut"/>
<aop:aspect ref="userServiceadvice">
<aop:before method="before" pointcut-ref="userServicePointcut"/>
<aop:after-returning method="afterReturning" pointcut-ref="userServicePointcut" returning="value"/>
<aop:around method="around" pointcut-ref="userServicePointcut" />
</aop:aspect>
</aop:config>
</beans>
IUserService接口

public interface IUserService {
public abstract String login();
public abstract void add();
public abstract void del();
}
UserServiceImp实现类

public class UserServiceImp implements IUserService{
@Override
public String login() {
System.out.println("login....method...");
return "123";
}
@Override
public void add() {
System.out.println("add");
}
@Override
public void del() {
System.out.println("del");
}
}
UserHelp类

public class UserHelp{
public void before(JoinPoint jp){
System.out.println("前置通知");
System.out.println("拦截目标类"+jp.getSignature().getDeclaringTypeName());
System.out.println("拦截方法名称"+jp.getSignature().getName());
}
public void afterReturning(JoinPoint jp,Object value){
System.out.println("后置通知");
System.out.println("返回值"+value);
}
public Object around(ProceedingJoinPoint mi) throws Throwable{
System.out.println("环绕前");
Object proceed = mi.proceed();
System.out.println("环绕后");
return proceed;
}
}
测试类

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations="classpath:applicationContext.xml")
public class AopTest {
@Autowired
private IUserService userService;
@Test
public void test01(){
userService.login();
System.out.println("------------");
userService.add();
System.out.println("-----------");
userService.del();
}
}
输出结果:

前置通知 拦截目标类com.baidu.aop.spring_aspectj.IUserService 拦截方法名称login 环绕前 login....method... 环绕后 后置通知 返回值123 ------------ 前置通知 拦截目标类com.baidu.aop.spring_aspectj.IUserService 拦截方法名称add 环绕前 add 环绕后 后置通知 返回值null ----------- 前置通知 拦截目标类com.baidu.aop.spring_aspectj.IUserService 拦截方法名称del 环绕前 del 环绕后 后置通知 返回值null
传统的方法实现aop开发: 在开发过程中applicationContext.xml配置文件中的配置项太多,eg:目标类,通知,切点,切面,代理,都需要我们去配置,
基于传统的aspectj实现aop思想: 在开发过程中applicationContext.xml配置文件中简化了许多,使用<aop:config></aop:config>标签来配置切点切面代理进行配置
aspectj的主要标签
<aop:config> 来声明要对 aop 进行配置 <aop:pointcut> 它是用于声明切点(简单说就是对哪些方法进行拦截) <aop:advisor> 定义传统的 aop 的切面,传统的 aop 切面它只能包含一个切点与一个增强 <aop:aspect> 定义 aspectj 框架的切面.,它可以包含多个切点与多个通知
spring框架整合aspectj实现aop思想: 在整合的过程中对于代理类中进行了修改,不需要继承或实现一些接口,降低了耦合性.在开发中很实用.
6.基于注解开发aop
applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:c="http://www.springframework.org/schema/c"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="http://www.springframework.org/schema/beans
http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
http://www.springframework.org/schema/tx/spring-tx.xsd">
<!-- 扫描spring注解 -->
<context:component-scan base-package="com.baidu"></context:component-scan>
<!-- 开启aspectj自动注解扫描 -->
<aop:aspectj-autoproxy/>
</beans>
IUserService接口

public interface IUserService {
public abstract String login();
public abstract void add();
public abstract void del();
}
UserServiceImp实现类

@Service
public class UserServiceImp implements IUserService{
@Override
public String login() {
System.out.println("login....method...");
return "123";
}
@Override
public void add() {
System.out.println("add");
}
@Override
public void del() {
System.out.println("del");
}
}
UserHelp增强类

@Component
@Aspect //声明切面
public class UserHelp{
@Before("execution(* com.baidu.aop.spring_anno_aspectj.IUserService.*(..))")
public void before(JoinPoint jp){
System.out.println("前置通知");
System.out.println("拦截目标类"+jp.getSignature().getDeclaringTypeName());
System.out.println("拦截方法名称"+jp.getSignature().getName());
}
@AfterReturning(value="execution(* com.baidu.aop.spring_anno_aspectj.IUserService.*(..))",returning="value")
public void afterReturning(JoinPoint jp,Object value){
System.out.println("后置通知");
System.out.println("返回值"+value);
}
@Around("execution(* com.baidu.aop.spring_anno_aspectj.IUserService.*(..))")
public Object around(ProceedingJoinPoint mi) throws Throwable{
System.out.println("环绕前");
Object proceed = mi.proceed();
System.out.println("环绕后");
return proceed;
}
}
测试类

@RunWith(SpringJUnit4ClassRunner.class) //整合junit4
@ContextConfiguration(locations="classpath:applicationContext.xml")//使用注解加载配置文件
public class AopTest {
@Autowired //依赖注入
private IUserService userService;
@Test
public void test01(){
userService.login();
System.out.println("------------");
userService.add();
System.out.println("-----------");
userService.del();
}
}
测试结果

环绕前 前置通知 拦截目标类com.baidu.aop.spring_anno_aspectj.IUserService 拦截方法名称login login....method... 环绕后 后置通知 返回值123 ------------ 环绕前 前置通知 拦截目标类com.baidu.aop.spring_anno_aspectj.IUserService 拦截方法名称add add 环绕后 后置通知 返回值null ----------- 环绕前 前置通知 拦截目标类com.baidu.aop.spring_anno_aspectj.IUserService 拦截方法名称del del 环绕后 后置通知 返回值null
修改UserHelp增强类 把切点提取出来,只需要在切面上引用就可以

@Component
@Aspect //声明切面
public class UserHelp{
@Pointcut("execution(* com.baidu.aop.spring_anno_aspectj.IUserService.*(..))")
public void mycut(){
}
@Before("mycut()")
public void before(JoinPoint jp){
System.out.println("前置通知");
System.out.println("拦截目标类"+jp.getSignature().getDeclaringTypeName());
System.out.println("拦截方法名称"+jp.getSignature().getName());
}
@AfterReturning(value="mycut()",returning="value")
public void afterReturning(JoinPoint jp,Object value){
System.out.println("后置通知");
System.out.println("返回值"+value);
}
@Around("mycut()")
public Object around(ProceedingJoinPoint mi) throws Throwable{
System.out.println("环绕前");
Object proceed = mi.proceed();
System.out.println("环绕后");
return proceed;
}
}
spring整合了aspectj框架他的底层代理方式默认为jdk代理方式来选择,如果没有接口则就是cglib代理方式.
<aop:aspectj-autoproxy proxy-target-class="false"></aop:aspectj-autoproxy>
Proxy-target-class 默认值是 false,代表的是如果目标是有接口的使用 proxy 代理,如果没有接 口使用 cglib. 如果将 proxy-target-class=true,不管目标是否有接口,都会使用 cglib 进行代理。
来源:https://www.cnblogs.com/fjkgrbk/p/spring_aop.html
