1.什么是AOP?

  AOP为 Aspect Oriented Programming 的缩写,即面向切面编程, 通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.。AOP是OOP的延续, 是函数式编程的一种衍生范型。利用AOP可以对业务逻辑的各个部分进行隔离, 从而使得业务逻辑各部分之间的耦合度降低, 提高程序的可重用性, 同时提高了开发的效率。

2.AOP与传统开发对比

  传统开发模型: 纵向的编程

  

  面向切面编程: 纵横配合的编程

  

3.为什么用AOP?

  在我们的项目中几乎每个业务都需要有事务控制、日志管理、权限控制等操作。这样就造成了需要写大量的重复代码。例如:

  

//模拟事务管理器
public class MyTransactionManager {
public void begin() {
System.out.println("开启事务");
} public void commit() {
System.out.println("提交事务");
} public void rollback() {
System.out.println("回滚事务");
} public void close() {
System.out.println("关闭session");
}
}
//Service层代码
public class UserServiceImpl implements UserService {
// 引入事务管理器
private MyTransactionManager txManager = new MyTransactionManager(); @Override
public void insert(String username) {
try {
txManager.begin();
System.out.println("调用dao层插入方法");
txManager.commit();
} catch (Exception e) {
txManager.rollback();
} finally {
txManager.close();
}
} @Override
public void update(String username) {
try {
txManager.begin();
System.out.println("调用dao层修改方法");
txManager.commit();
} catch (Exception e) {
txManager.rollback();
} finally {
txManager.close();
}
}
}

每个需要对数据库数据进行修改的业务都要进行事务处理,就会有大量的重复代码,所以就需要用APO来减少重复代码、提高开发效率、方便维护。

4.AOP的实现方式(原理)

  AOP的底层是使用动态代理模式来实现的。(JDK动态代理和CGLIB代理技术)
  动态代理,就是使用者使用的不是真实的对象,而是使用的一个代理对象,而这个代理对象中包含的就是真实的对象,代理对象就是不改变原有对象的功能方法的基础之上封装新的功能。
  AOP的原理就是把需要增强的代码(重复的代码)定义在代理类中,本身只保留核心的代码。在方法运行时切到代理对象中执行。

  

5.JDK动态代理

  JDK动态代理是Java官方的代理,使用JDK官方的Proxy类创建代理对象。

  5.1 java.lang.reflect.Proxy 类:

Java 动态代理机制生成的所有动态代理类的父类,它提供了一组静态方法来为一组接口动态地生成代理类及其对象。
主要方法:public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces,InvocationHandler hanlder)
参数:

loader :类加载器
interfaces : 模拟的接口
hanlder :代理执行处理器(通过实现java.lang.reflect.InvocationHandler接口)

方法职责:为指定类加载器、一组接口及调用处理器生成动态代理类实例
返回:动态生成的代理对象

  5.2 java.lang.reflect.InvocationHandler接口:

public Object invoke(Object proxy, Method method, Object[] args)
参数:

proxy :生成的代理对象
method :当前调用的真实方法对象
args :当前调用方法的实参

方法职责:负责集中处理动态代理类上的所有方法调用
返回: 真实方法的返回结果

5.3 示例代码:

需要的jar包:

  整体结构:

pojo类

package com.gjs.pojo;

public class User {
private Integer id;
private String name;
private Integer age; public Integer getId() {
return id;
}
public void setId(Integer id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public User() {
super();
}
public User(Integer id, String name, Integer age) {
super();
this.id = id;
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User [id=" + id + ", name=" + name + ", age=" + age + "]";
} }

service层

package com.gjs.service.impl;

import com.gjs.pojo.User;
import com.gjs.service.UserService; public class UserServiceImpl implements UserService { @Override
public void insert(User user) {
System.out.println("调用dao层插入方法");
} @Override
public void update(User user) {
System.out.println("调用dao层修改方法");
} }

模拟事务管理器

package com.gjs.util;

//模拟事务管理器
public class MyTransactionManager {
public void begin() {
System.out.println("开启事务");
} public void commit() {
System.out.println("提交事务");
} public void rollback() {
System.out.println("回滚事务");
} public void close() {
System.out.println("关闭session");
}
}

JDK动态代理类:

package com.gjs.proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy; import com.gjs.util.MyTransactionManager;
//JDK动态代理类
public class DynamicProxyHandeler {
private Object target; // 被代理的对象
private MyTransactionManager manager; // 事务管理器 public void setTarget(Object target) {
this.target = target;
} public void setManager(MyTransactionManager manager) {
this.manager = manager;
} public <T> T getProxyObject(Class<T> clz) { ClassLoader loader = this.getClass().getClassLoader();// 类加载器
Class<?>[] interfaces = clz.getInterfaces();// 被代理对象的接口
// InvocationHandler():Proxy的处理器,具体做正在增强的地方(需要开发者自己实现)
Object proxyInstance = Proxy.newProxyInstance(loader, interfaces, new InvocationHandler() { /**
* 处理器中具体做增强的方法
*
* @param proxy
* 代理对象
* @param method
* 被代理对象的方法
* @param args
* 被代理对象方法的参数
* @return 被代理对象方法执行以后的结果
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
// 1.开启事务
manager.begin(); // 执行被代理对象的犯法
result = method.invoke(target, args); // 2.提交事务
manager.commit();
} catch (Exception e) {
e.printStackTrace();
// 3.回滚事务
manager.rollback();
} finally {
// 4.关闭session
manager.close();
}
return result;
}
});
return (T) proxyInstance;
}
}

配置文件:applicationContext.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd
"> <!-- 配置模拟的事务管理器 -->
<bean id="manager" class="com.gjs.util.MyTransactionManager"/> <!-- 配置代理类 -->
<bean id="dynamicProxyHandeler" class="com.gjs.proxy.DynamicProxyHandeler">
<!-- 注入被代理的对象 -->
<property name="target" >
<bean class="com.gjs.service.impl.UserServiceImpl"/>
</property>
<!-- 注入事务管理器 -->
<property name="manager" ref="manager"/>
</bean> </beans>

测试类

package com.gjs.test;

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; import com.gjs.pojo.User;
import com.gjs.proxy.DynamicProxyHandeler;
import com.gjs.service.UserService;
import com.gjs.service.impl.UserServiceImpl; //表示先启动Spring容器,把junit运行在Spring容器中
@RunWith(SpringJUnit4ClassRunner.class)
// 表示从哪里加载资源文件,默认从src(源目录)下面加载
@ContextConfiguration("classpath:applicationContext.xml")
public class TestSpring {
// 注入代理类的对象
@Autowired
private DynamicProxyHandeler dynamicProxyHandeler; @Test
public void testInsert() throws Exception {
// 通过代理类获取代理对象
UserService proxyObject = dynamicProxyHandeler.getProxyObject(UserServiceImpl.class);
User user = new User(null, "张三", 18);
proxyObject.insert(user);
} @Test
public void testUpdate() throws Exception {
// 通过代理类获取代理对象
UserService proxyObject = dynamicProxyHandeler.getProxyObject(UserServiceImpl.class);
User user = new User(1, "李四", 18); // 执行代理对象的修改方法
proxyObject.update(user);
} @Test
public void test1() throws Exception {
// 通过代理类获取代理对象
UserService proxyObject = dynamicProxyHandeler.getProxyObject(UserServiceImpl.class);
proxyObject.toString();
}
}

5.4 JDK动态代理的不足

1.JDK动态代理的对象必须要实现一个接口
2.需要为每个对象创建代理对象
3.动态代理的最小单位是类(所有类中的方法都会被处理),查询方法不需要事务,可能不需要被代理

6.CGLIB动态代理

  CGLIB和JDK动态代理一样都是动态代理,不同的是CGLIB代理没有接口也可以进行代理,而且在Spring中已经集成了CGLIB代理,可以直接使用,不需要再导入其他jar包。
  CGLIB代理使用Enhancer类代理

  

  6.1 示例代码:

  动态代理类:

package com.gjs.proxy;

import java.lang.reflect.Method;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.InvocationHandler; import com.gjs.util.MyTransactionManager;
//CGLIB动态代理类
public class DynamicProxyHandeler {
private Object target; // 被代理的对象
private MyTransactionManager manager; // 事务管理器 public void setTarget(Object target) {
this.target = target;
} public void setManager(MyTransactionManager manager) {
this.manager = manager;
} public <T> T getProxyObject(Class<T> clz) { ClassLoader loader = this.getClass().getClassLoader();// 类加载器
Enhancer enhancer = new Enhancer();
enhancer.setClassLoader(loader); // 设置类加载器
enhancer.setSuperclass(target.getClass()); // 设置代理对象的class /*
* 代理的具体实现 InvocationHandler:org.springframework.cglib.proxy.InvocationHandler
*/
enhancer.setCallback(new InvocationHandler() {
/**
* 处理器中具体做增强的方法
*
* @param proxy
* 代理对象
* @param method
* 被代理对象的方法
* @param args
* 被代理对象方法的参数
* @return 被代理对象方法执行以后的结果
* @throws Throwable
*/
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = null;
try {
// 1.开启事务
manager.begin(); // 执行被代理对象的犯法
result = method.invoke(target, args); // 2.提交事务
manager.commit();
} catch (Exception e) {
e.printStackTrace();
// 3.回滚事务
manager.rollback();
} finally {
// 4.关闭session
manager.close();
}
return result;
}
});
Object proxyObject = enhancer.create();// 创建代理对象
return (T) proxyObject;
}
}

  其他代码参考jdk动态代理的示例代码

6.2 CGLIB动态代理使用要点

1,CGLIB可以生成目标类的子类,并重写父类非final修饰符的方法。
2,要求类不能是final的,要代理的方法要是非final、非static、非private的。
3,动态代理的最小单位是类(所有类中的方法都会被处理);

7. 直接使用动态代理的缺陷

1.直接使用代理虽然解决代码重复问题,但却需要在配置文件中为每一个类都配置代理类
2.无法通过规则制定要拦截的方法,所有方法都会进行代理。例如:查询的方法不需要进行事务处理、toString方法不需要代理。

  Spring提供了AOP的实现就能解决这些问题。

8.Spring的AOP

Spring的AOP可以通过规则设置来拦截方法,加入可以统一处理的代码。并且spring会根据目标类是否实现了接口来决定采用哪种动态代理的方式:
  若目标对象实现了接口,Spring就会使用JDK动态代理。
  若目标对象没有实现任何接口,Spring就使用CGLIB库生成目标对象的子类。

AOP相关术语:

Joinpoint(连接点):所谓连接点是指那些被拦截到的点。在spring中,这些点指的是方法,因为spring只支持方法类型的连接点。即根据规则指定拦截的方法,我们将每一个被拦截的方法称为连接点。

Pointcut(切入点):切入点就是拦截方法设置的规则,即需要对哪些Joinpoint进行拦截的定义。

Advice(通知/增强):设置在方法之前拦截或者方法执行之后拦截或者方法出异常后拦截,或者方法之前和之后都拦截。我们将这些拦截场景称为通知。 所谓通知是指拦截到Joinpoint之后所要做的事情就是通知。通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。

Aspect(切面):切面就是我们的拦截处理类。是切入点和通知的结合。

Weaving(织入):把切面加入到对象,并创建出代理对象的过程。(这个过程由Spring自动来完成)

9.基于XML配置AOP

  整体结构:

1.导入相关jar

  AOP 思想必须使用AspectJ语法,而AOP思想不是Spring框架设计出来的,而是叫一个AOP联盟组织提出这种思想,所以需要导入 AOP联盟提供的 aspectjweaver.jar(aspectweaver织入包)

  2.创建配置文件并引入声明及命名空间

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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.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
"> </beans>

  3.编写一个切面类

package com.gjs.util;

//模拟事务管理器
public class MyTransactionManager {
public void begin() {
System.out.println("开启事务");
} public void commit() {
System.out.println("提交事务");
}
//Throwable e 参数名和 aop 异常增强的 after-throwing 的值相同
public void rollback(Throwable e) {
e.printStackTrace();
System.out.println("回滚事务");
} public void close() {
System.out.println("关闭session");
}
}

  4.添加AOP配置

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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.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
"> <!-- 配置事务管理器 -->
<bean id="manager" class="com.gjs.util.MyTransactionManager"/> <!-- 配置service实现类 -->
<bean id="service" class="com.gjs.service.impl.UserServiceImpl"/> <!--
AOP配置: W (where)W(when)W(what) 原则
where:从哪里切入
when:什么时候
what:做什么
--> <!-- proxy-target-class:是否是基于类的代理 (CGLIB代理)。
如果出现service类注入时注入了代理对象可以使用该属性-->
<aop:config proxy-target-class="true">
<!--
配置切入点(Pointcut):在哪些类,哪些方法上切入(where)
expression:切入点表达式
id:切入点唯一标识
-->
<aop:pointcut expression="execution(* com.gjs.service..*.*(..))" id="pt"/> <!-- 配置切面 = 切入点(pointcut)+ 通知/增强(advice)
ref : 引入需要增强的事务管理器
-->
<aop:aspect ref="manager">
<!--
when :什么时候
之前(before)
之后(after-returning)
异常(after-throwing)
最终(after))
-->
<!-- what:做什么(method) -->
<!-- where:从哪里切入(pointcut-ref) -->
<aop:before method="begin" pointcut-ref="pt"/>
<aop:after-returning method="commit" pointcut-ref="pt"/>
<!-- 异常增强
throwing : 异常,值 必须和对应方法名称的 参数名称一样
抛出的是顶级异常Throwable
-->
<aop:after-throwing method="rollback" pointcut-ref="pt" throwing="e"/>
<aop:after method="close" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
</beans>

  测试类

package com.gjs.test;

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; import com.gjs.pojo.User;
import com.gjs.service.impl.UserServiceImpl; //表示先启动Spring容器,把junit运行在Spring容器中
@RunWith(SpringJUnit4ClassRunner.class)
//表示从哪里加载资源文件,默认从src(源目录)下面加载
@ContextConfiguration("classpath:applicationContext.xml")
public class TestSpring {
// 注入代理类的对象
@Autowired
private UserServiceImpl service; @Test
public void testInsert() throws Exception {
User user = new User(null, "张三", 18);
service.insert(user);
} @Test
public void testUpdate() throws Exception {
User user = new User(1, "李四", 18);
service.update(user);
} @Test
public void test1() throws Exception {
service.toString();
}
}

其他代码参考动态代理的示例代码

环绕增强(环绕通知方式)

切面类

package com.gjs.util;

import org.aspectj.lang.ProceedingJoinPoint;

//模拟事务管理器
public class MyTransactionManager { public void allInOne(ProceedingJoinPoint pjo) {
try {
System.out.println("开启事务"); //执行具体的方法
pjo.proceed(); System.out.println("提交事务"); } catch (Throwable e) {
System.out.println("回滚事务"); }finally {
System.out.println("关闭session");
} }
}

配置文件

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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.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
"> <!-- 配置事务管理器 -->
<bean id="manager" class="com.gjs.util.MyTransactionManager"/> <!-- 配置service实现类 -->
<bean id="service" class="com.gjs.service.impl.UserServiceImpl"/> <!--
AOP配置: W (where)W(when)W(what) 原则
where:从哪里切入
when:什么时候
what:做什么
--> <!-- proxy-target-class:是否是基于类的代理 (CGLIB代理)。
如果出现service类注入时注入了代理对象可以使用该属性-->
<aop:config proxy-target-class="true">
<!--
配置切入点(Pointcut):在哪些类,哪些方法上切入(where)
expression:切入点表达式
id:切入点唯一标识
-->
<aop:pointcut expression="execution(* com.gjs.service..*.*(..))" id="pt"/> <!-- 配置切面 = 切入点(pointcut)+ 通知/增强(advice)
ref : 引入需要增强的事务管理器
-->
<aop:aspect ref="manager">
<!-- 环绕增强:Spring事务管理就是使用环绕增强 -->
<aop:around method="allInOne" pointcut-ref="pt"/>
</aop:aspect>
</aop:config>
</beans>

10.切入点表达式说明

execution(表达式)

  表达式语法:execution([修饰符] 返回值类型 包名.类名.方法名(参数))

写法说明:(常用)

全匹配方式:
  public void com.gjs.service.impl.CustomerServiceImpl.saveCustomer()
访问修饰符可以省略 :
  void com.zj.service.impl.CustomerServiceImpl.saveCustomer()
返回值可以使用*号,表示任意返回值:
  * com.zj.service.impl.CustomerServiceImpl.saveCustomer()
包名可以使用*号,表示任意包,但是有几级包,需要写几个*:
  * *.*.*.*.CustomerServiceImpl.saveCustomer()
使用..来表示当前包,及其子包:
  * com..CustomerServiceImpl.saveCustomer()
类名可以使用*号,表示任意类:
  * com..*.saveCustomer()
方法名可以使用*号,表示任意方法:
  * com..*.*()
参数列表可以使用*,表示参数可以是任意数据类型,但是必须有参数:
  * com..*.*(*)
参数列表可以使用..表示有无参数均可,有参数可以是任意类型:
  * com..*.*(..)
全通配方式:
  * *..*.*(..)

11.常用标签

11.1.<aop:config>

  作用:用于声明开始aop的配置

11.2.<aop:aspect>

作用:用于配置切面。
属性:
id:给切面提供一个唯一标识。
ref:引用配置好的通知类bean的id。

11.3.<aop:pointcut>

作用:用于配置切入点表达式
属性:
expression:用于定义切入点表达式。
id:用于给切入点表达式提供一个唯一标识。

11.4.<aop:before>

作用:用于配置前置通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用

11.5.<aop:after-returning>

作用:用于配置后置通知,如果出了异常就一定不会调用切面的方法
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用

11.6.<aop:after-throwing>

作用:用于配置异常通知,只有出了异常才会调用切面对应的方法
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用

11.7.<aop:after>

作用: 用于配置最终通知,不管出不出异常,调用的切面的方法
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用

11.8.<aop:around>

作用:用于配置环绕通知
属性:
method:指定通知中方法的名称。
pointct:定义切入点表达式
pointcut-ref:指定切入点表达式的引用

12.基于注解配置AOP

  12.1 示例代码:

  切面类:

package com.gjs.util;

import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component; //事务管理器
@Component
@Aspect //声明此类为切面类, 等价于 <aop:aspect ref="manager">
public class MyTransactionManager { //设置切入点
@Pointcut("execution(* com.gjs.service..*.*(..))")
//相当于<aop:pointcut expression="execution(* com.gjs.service..*.*(..))" id="pt"/>
public void pointcut() {} @Before("pointcut()")//相当于<aop:before method="begin" pointcut-ref="pt"/>
public void begin() {
System.out.println("开启事务");
}
@After("pointcut()")//相当于<aop:after-returning method="commit" pointcut-ref="pt"/>
public void commit() {
System.out.println("提交事务");
}
@AfterThrowing(pointcut="pointcut()",throwing="e")
// 相当于<aop:after-throwing method="rollback" pointcut-ref="pt" throwing="ex"/>
public void rollback(Throwable e) {
e.printStackTrace();
System.out.println("回滚事务");
}
@AfterReturning("pointcut()")//相当于<aop:after method="close" pointcut-ref="pt"/>
public void close() {
System.out.println("关闭session");
}
}

  配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:p="http://www.springframework.org/schema/p"
xmlns:context="http://www.springframework.org/schema/context"
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.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
"> <!-- 配置service实现类 -->
<bean id="service" class="com.gjs.service.impl.UserServiceImpl"/> <!-- 配置注解组件扫描的包位置 -->
<context:component-scan base-package="com.gjs"/> <!-- 开启spring aop的注解配置 -->
<!-- proxy-target-class="true",是否要创建基于类的代理(CGLIB),默认创建JDK动态代理,可能会出现service实现类注入不了的问题 -->
<aop:aspectj-autoproxy proxy-target-class="true"></aop:aspectj-autoproxy>
</beans>

其他代码参考xml方式

  12.2环绕通知方式:(一般用这种方式)

  切面类:

package com.gjs.util;

import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.stereotype.Component; //模拟事务管理器
@Component
@Aspect // 声明此类为切面类, 等价于 <aop:aspect ref="manager">
public class MyTransactionManager {
// 设置切入点,相当于<aop:pointcut expression="execution(* com.gjs.service..*.*(..))" id="pt"/>
@Pointcut("execution(* com.gjs.service..*.*(..))")
public void pointcut() {
}
@Around("pointcut()")//相当于<aop:around method="allInOne" pointcut-ref="pt"/>
public void allInOne(ProceedingJoinPoint pjo) { try {
System.out.println("开启事务"); // 执行具体的方法
pjo.proceed(); System.out.println("提交事务"); } catch (Throwable e) {
System.out.println("回滚事务"); } finally {
System.out.println("关闭session");
} }
}

配置文件与上面相同

13.常用注解

13.1 @Aspect

  作用:把当前类声明为切面类。

13.2 @Pointcut

作用:指定切入点表达式
属性:
value:指定表达式的内容

13.3 @Before

作用:把当前方法看成是前置通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

13.4 @After

作用:把当前方法看成是后置通知。报异常,就不执行
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

13.5 @AfterThrowing

作用:把当前方法看成是异常通知。只有报异常才执行
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

13.6 @AfterReturning

作用:把当前方法看成是最终通知。不管报不报异常都执行
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

13.7 @Around

作用:把当前方法看成是环绕通知。
属性:
value:用于指定切入点表达式,还可以指定切入点表达式的引用。

注: @After和@AfterReturning 并没有写反,至于为什么从命名和xml方式相反就不得而知了,可能是当时Spring的作者写错了,后面也没有去改正

深入学习Spring框架(三)- AOP面向切面的更多相关文章

  1. Spring(三)面向切面编程(AOP)

    在直系学长曾经的指导下,参考了直系学长的博客(https://www.cnblogs.com/WellHold/p/6655769.html)学习Spring的另一个核心概念--面向切片编程,即AOP ...

  2. Spring Boot2(六):使用Spring Boot整合AOP面向切面编程

    一.前言 众所周知,spring最核心的两个功能是aop和ioc,即面向切面和控制反转.本文会讲一讲SpringBoot如何使用AOP实现面向切面的过程原理. 二.何为aop ​ aop全称Aspec ...

  3. spring框架学习(三)——AOP( 面向切面编程)

    AOP 即 Aspect Oriented Program 面向切面编程 首先,在面向切面编程的思想里面,把功能分为核心业务功能,和周边功能. 所谓的核心业务,比如登陆,增加数据,删除数据都叫核心业务 ...

  4. Spring(3):AOP面向切面编程

    一,AOP介绍 AOP为Aspect Oriented Programming的缩写,意为:面向切面编程,通过预编译方式和运行期动态代理实现程序功能的统一维护的一种技术.AOP是OOP的延续,是软件开 ...

  5. Spring注解式AOP面向切面编程.

    1.AOP指在程序运行期间动态的将某段代码切入到指定方法指定位置进行运行的编程方式.aop底层是动态代理. package com.bie.config; import org.aspectj.lan ...

  6. 【Spring 核心】AOP 面向切面编程

    一.什么是面向切面编程? 二.通过切点来选择连接点 三.使用注解创建切面 四.在XML中声明切面 五.注入AspectJ切面

  7. Spring Boot之AOP面向切面编程-实战篇

    目录 前言 编程范式主要有以下几类 引入pom依赖 aop注解 实现日志分割功能 前言 AOP是一种与语言无关的程序思想.编程范式.项目业务逻辑中,将通用的模块以水平切割的方式进行分离统一处理,常用于 ...

  8. Spring框架系列(五)--面向切面AOP

    背景: 当需要为多个不具有继承关系的对象引入一个公共行为,例如日志.权限验证.事务等功能时,如果使用OOP,需要为每个对象引入这些公共 行为.会产生大量重复代码,并且不利用维护.AOP就是为了解决这个 ...

  9. Spring(三)AOP面向切面编程

    原文链接:http://www.orlion.ga/205/ 一.AOP简介 1.AOP概念 参考文章:http://www.orlion.ml/57 2.AOP的产生 对于如下方法:     pub ...

  10. Guice 学习(八)AOP (面向切面的编程)

    Guice的AOP还是非常弱的.眼下只支持方法级别上的,另外灵活性也不是非常高. 看例如以下演示样例: Guice支持AOP的条件是: 类必须是public或者package (default) 类不 ...

随机推荐

  1. Python编写AWS Version 4 signing (AWS4-HMAC-SHA256) for execute-api

    官网教程中给了签署AWS请求给了详细的介绍和python的例子,但是例子针对DynamoDB API,本例子针对API Gateway的POST请求,并携带有x-amz-security-token. ...

  2. 聊聊浏览器(webkit)资源加载机制

    一些准备 在开始这个话题之前,我们有必要简单回顾一下 浏览器(webkit)的网页渲染过程(如果想要详细了解这个过程,可以戳我几年前写的一篇文章.): 我们知道,浏览器在渲染过程中,如遇到节点需要依赖 ...

  3. iOS-HTTP浅析

    HTTP原理 什么是URL URL中常见的几种协议 什么是HTTP协议 HTTP是做什么的 为什么要使用HTTP协议 HTPP协议的通信过程介绍 HTTP请求 HTTP响应 HTTP请求的选择 两种发 ...

  4. 恢复Win10照片查看器

    批处理文件: @echo off&cd\&color 0a&cls echo 恢复Win10照片查看器 reg add "HKLM\SOFTWARE\Microsof ...

  5. 使用ArcGIS Server发布我们的数据

    原文:使用ArcGIS Server发布我们的数据 引言 上一篇我们已经安装好了ArcGIS体系的服务软件,这一篇将介绍如何把我们自己的数据通过ArcGIS Server发布出去,并且能够通过Web页 ...

  6. C#WebBroswer控件的使用

    在WebBroswer中可以嵌入一个网页文件,通过Url属性绑定. URI,统一资源标识符,用来唯一的标识一个资源. URL,统一资源定位器,它是一种具体的URI,即URL可以用来标识一个资源. 它包 ...

  7. Office Add-in Model 为 Outlook Mail Add-in 提供的 JavaScript API 介绍

    本文所讨论的 Mailbox API是指在 Mail Add-in 中可调用的 JavaScript API.开发者可以利用这些API 实现 Add-in 和 Outlook 的交互(数据读取与写入) ...

  8. Delphi中文件流的使用方法

    在Delphi中,所有流对象的基类为TStream类, 其中定义了所有流的共同属性和方法.TStream类中定义的属性介绍如下: 1.Size: 此属性以字节返回流中数据大小. 2.Position: ...

  9. VS2010下编译配置Boost_1.53

    一.准备工作 1.下载最新版本的boost库.所在地址:boost_1_53_0.zip.官方推荐7z压缩格式的,因为其压缩效率更好,相应包的大小也比较小. 2.解压缩到指定目录,如C:\boost_ ...

  10. hive -e和hive -f的区别(转)

    大家都知道,hive -f 后面指定的是一个文件,然后文件里面直接写sql,就可以运行hive的sql,hive -e 后面是直接用双引号拼接hivesql,然后就可以执行命令. 但是,有这么一个东西 ...