1. 什么是AOP?
2. Spring底层的AOP实现原理
2.1. AOP应用场景
2.2. Spring动态代理
2.2.1. JDK动态代理: 只能对实现了接口的类产生代理。
2.2.2. CGLIB动态代理: 对没有实现接口的类产生代理。CGLIB(Code Generation Library)是一个开源的, 强大的, 高性能, 高质量的Code生成类库。Spring引入了它。
3. AOP简介
3.1. AOP思想最早是由AOP联盟组织提出的。Spring是使用这种思想的最好的框架。
3.2. AspectJ是一个面向切面的框架, 它扩展了Java语言。
3.3. Spring早期的AOP是自己实现的, 但是十分繁琐。后来Spring引入了AspectJ进行AOP开发。
4. AOP术语
5. Spring中通知类型
5.1. 前置通知: 在目标方法执行之前进行操作。
5.2. 后置通知: 在目标方法执行之后进行操作。
5.3. 环绕通知: 在目标方法执行之前和之后进行操作。
5.4. 异常抛出通知: 在程序出现异常的时候进行操作。
5.5. 最终通知: 无论代理是否有异常, 总会执行。
6. 切入点表达式语法
6.1. 基于execution的函数完成的。
6.2. [访问修饰符] 返回值类型 包名.类名.方法名(参数), 访问修饰符可以省略不写。
6.3. public void com.lywgames.dao.impl.UserDaoImpl.insert(..), 参数使用.., 表示任意参数。
6.4. * com.lywgames.dao.impl.UserDaoImpl.insert(..), 返回值使用*, 表示任意返回值类型。
6.5. * com..UserDaoImpl.insert(..), 包路径可以使用..做省略, 但是必须有开头。
6.6. * com.lywgames.dao.impl.*.*(..), 该包下的所有类的所有方法。
7. 引入aop的约束
8. 切入点配置
9. 通知配置
10. JDK动态代理例子
10.1. 新建一个名为JdkProxy的Java项目
10.2. 创建UserDao.java接口
package com.lywgames.dao;
public interface UserDao {
void insert();
void select();
void update();
void delete();
}
10.3. 创建UserDao.java接口的实现类UserDaoImpl.java
package com.lywgames.dao.impl;
import com.lywgames.dao.UserDao;
public class UserDaoImpl implements UserDao {
@Override
public void insert() {
System.out.println("插入User对象。");
}
@Override
public void select() {
System.out.println("查询User对象。");
}
@Override
public void update() {
System.out.println("更新User对象。");
}
@Override
public void delete() {
System.out.println("删除User对象。");
}
}
10.4. 创建JDKProxy.java代理类
package com.lywgames.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import com.lywgames.dao.UserDao;
public class JDKProxy implements InvocationHandler{
private UserDao userDao;
public JDKProxy(UserDao userDao) {
this.userDao = userDao;
}
public UserDao createProxy() {
return (UserDao)Proxy.newProxyInstance(userDao.getClass().getClassLoader(), userDao.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
if("select".equals(method.getName())) {
System.out.println("查询User对象前, 对其进行校验。");
return method.invoke(userDao, args);
}
return method.invoke(userDao, args);
}
}
10.5. 创建Test.java测试类
package com.lywgames;
import com.lywgames.dao.UserDao;
import com.lywgames.dao.impl.UserDaoImpl;
import com.lywgames.proxy.JDKProxy;
public class Test {
public static void main(String[] args) {
UserDao userDao = new UserDaoImpl();
JDKProxy jdkProxy = new JDKProxy(userDao);
UserDao proxy = jdkProxy.createProxy();
proxy.insert();
proxy.select();
proxy.update();
proxy.delete();
}
}
10.6. 运行项目
11. CGLIB动态代理例子
11.1. 新建一个名为CglibProxy的Java项目, 拷入spring-core.java, 她有CGLIB代码
11.2. 创建UserDaoImpl.java类
package com.lywgames.dao.impl;
public class UserDaoImpl {
public void insert() {
System.out.println("插入User对象。");
}
public void select() {
System.out.println("查询User对象。");
}
public void update() {
System.out.println("更新User对象。");
}
public void delete() {
System.out.println("删除User对象。");
}
}
11.3. 创建CglibProxy.java代理类
package com.lywgames.proxy;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import com.lywgames.dao.impl.UserDaoImpl;
public class CglibProxy implements MethodInterceptor {
private UserDaoImpl userDaoImpl;
public CglibProxy(UserDaoImpl userDaoImpl) {
this.userDaoImpl = userDaoImpl;
}
// 使用cglib产生代理
public UserDaoImpl createProxy() {
// 创建cglib的核心类
Enhancer enhancer = new Enhancer();
// 设置父类
enhancer.setSuperclass(userDaoImpl.getClass());
// 设置回调
enhancer.setCallback(this);
// 返回增强对象
return (UserDaoImpl)enhancer.create();
}
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
if("insert".equals(method.getName())) {
System.out.println("插入User对象前, 对其进行校验。");
return methodProxy.invokeSuper(proxy, args);
}
return methodProxy.invokeSuper(proxy, args);
}
}
11.4. 创建Test.java测试类
package com.lywgames;
import com.lywgames.dao.impl.UserDaoImpl;
import com.lywgames.proxy.CglibProxy;
public class Test {
public static void main(String[] args) {
UserDaoImpl userDaoImpl = new UserDaoImpl();
CglibProxy cglibProxy = new CglibProxy(userDaoImpl);
UserDaoImpl proxy = cglibProxy.createProxy();
proxy.insert();
proxy.select();
proxy.update();
proxy.delete();
}
}
11.5. 运行项目
12. AOP使用XML配置例子
12.1. 新建一个名为AOPXml的Java项目
12.2. 创建UserDao.java接口
package com.lywgames.dao;
public interface UserDao {
public void insert();
public void select();
public void update();
public int delete();
}
12.3. 创建UserDao.java接口的实现类UserDaoImpl.java
package com.lywgames.dao.impl;
import com.lywgames.dao.UserDao;
public class UserDaoImpl implements UserDao {
public void insert() {
System.out.println("插入数据");
}
public void select() {
System.out.println("查询数据");
}
public void update() {
System.out.println("更新数据");
throw new RuntimeException();
}
public int delete() {
System.out.println("删除数据");
return 1;
}
}
12.4. 创建AspectJAop.java切面类
package com.lywgames.aop;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
public class AspectJAop {
public void beforeInsertCheck(JoinPoint jp) {
System.out.println("检测插入数据, " + jp);
}
public void afterDelete(int result) {
System.out.println("删除后返回值: " + result);
}
public Object arround(ProceedingJoinPoint joinPoint) {
try {
System.out.println("查询前鼓鼓掌。");
Object obj = joinPoint.proceed();
System.out.println("查询后鼓鼓掌。");
return obj;
} catch (Throwable e) {
e.printStackTrace();
}
return null;
}
public void updateException(Throwable ex) {
System.out.println("更新发生了异常:" + ex.toString());
}
public void myFinally() {
System.out.println("更新方法发生了异常, 最终通知一样会执行完成。");
}
}
12.5. 创建AopAction.java测试类
package com.lywgames.action;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import com.lywgames.dao.UserDao;
public class AopAction {
public static void main(String[] args) {
ClassPathXmlApplicationContext context = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = context.getBean(UserDao.class);
userDao.insert();
userDao.delete();
userDao.select();
userDao.update();
context.close();
}
}
12.6. 在src目录下添加applicationContext.xml配置
<?xml version="1.0" encoding="UTF-8"?>
<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="userDao" class="com.lywgames.dao.impl.UserDaoImpl"></bean>
<bean id="aspectJAop" class="com.lywgames.aop.AspectJAop"></bean>
<!-- 通过aop的配置完成对目标类产生代理 -->
<aop:config>
<!-- 表达式配置哪些类的哪些方法需要进行增强 -->
<aop:pointcut expression="execution(* com..UserDaoImpl.insert(..))" id="pointinsert" />
<aop:pointcut expression="execution(* com.lywgames.dao.impl.UserDaoImpl.delete(..))" id="pointdelete"/>
<aop:pointcut expression="execution(* com.lywgames.dao.impl.UserDaoImpl.select(..))" id="pointselect"/>
<aop:pointcut expression="execution(* com.lywgames.dao.impl.UserDaoImpl.update(..))" id="pointupdate"/>
<!-- 配置切面 -->
<aop:aspect ref="aspectJAop"><!-- 引用切面类 -->
<!-- 前置通知 -->
<aop:before method="beforeInsertCheck" pointcut-ref="pointinsert" />
<!-- 后置通知 -->
<aop:after-returning method="afterDelete" pointcut-ref="pointdelete" returning="result"/>
<!-- 环绕通知 -->
<aop:around method="arround" pointcut-ref="pointselect"/>
<!-- 异常通知 -->
<aop:after-throwing method="updateException" pointcut-ref="pointupdate" throwing="ex" />
<!-- 最终通知 -->
<aop:after method="myFinally" pointcut-ref="pointupdate"/>
</aop:aspect>
</aop:config>
</beans>
12.7. 运行项目