Spring中的Aop
1、什么是AOP?
面向切面编程。利用它可以对业务逻辑的各个部分进行隔离,从而使得业务部分之间的耦合度降低,提高程序开发效率。
应用场景有:日志记录、性能统计、安全控制、事务处理、异常处理...
通俗描述:不通过修改源代码方式,在主干功能里添加新功能
AOP底层原理:
1、底层使用了动态代理
(1)有两种情况的动态代理
第一种:有接口,使用JDK动态代理
(1)调用newProxyInstance方法
方法三个参数:
第一:类加载器
第二:增强方法所在的类,这个类实现的接口,支持多个接口
第三:实现这个接口InvocationHandler,创建代理对象,写增强方法,示例代码如下:
public class ProxyJDK { public static void main(String[] args) { //创建接口实现类代理对象 Class[] interfaces = {UserDao.class}; /* Proxy.newProxyInstance(ProxyJDK.class.getClassLoader(), interfaces, new InvocationHandler() { @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { return null; } });*/ UserDaoImpl userDao=new UserDaoImpl(); UserDao dao = (UserDao) Proxy.newProxyInstance(ProxyJDK.class.getClassLoader(), interfaces, new UserDaoProxy(userDao)); dao.update(); } } //创建代理对象代码 class UserDaoProxy implements InvocationHandler { //创建的是谁的代理对象,把谁传过来,有参构造器 private Object obj; public UserDaoProxy(Object obj) { this.obj = obj; } //增强部分 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { //方法之前 System.out.println("开始增强" + method.getName() + ":传递的参数.." + Arrays.toString(args)); //被增强的方法执行 Object invoke = method.invoke(obj, args); //方法之后 System.out.println("执行结束" + obj); return null; } }
创建接口实现类代理对象,增强类的方法
第二种:没有接口情况,使用CGLIB动态代理
创建子类的代理对象,增强类的方法
AOP术语:
1、连接点:类里哪些方法可以被增强,这些方法称为切入点
2、切入点:实际被真正增强的方法
3、通知(增强):实际增强的逻辑部分
类型有:
前置通知:
后置通知:
环绕通知:
异常通知:
最终通知:
4、切面:是动作,把通知应用到切入点的过程
AOP操作:
1、一般基于AspectJ实现。
2、基于AspectJ实现AOP操作:
(1)基于xml配置文件
(2)基于注解方式(常用)
3、需要引入的依赖:
其中aspectj.weaver包用下面的包代替:
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.8.7</version> </dependency>
4、切入点表达式:
(1)作用:知道对哪个类里的哪个方法进行增强
(2):语法结构:
execution([权限修饰符][返回类型][类全路径][方法名称]([参数列表]))
示例:对com.zhaojianhui.dao.Bookdao类里的add方法增强
execution(* com.zhaojianhui.dao.Bookdao.add(..))
示例:对com.zhaojianhui.dao.Bookdao类里的所有方法增强
execution(* com.zhaojianhui.dao.Bookdao.*(..))
示例:对com.zhaojianhui.dao包里所有类,类里的所有方法增强
execution(* com.zhaojianhui.dao.*.*(..))
AOP操作(注解方式)
1、创建类,在类中定义方法
public class User { public void add(){ System.out.println("add..."); } }
2、创建增强类(编写增强逻辑)
//增强类 public class UserProxy { //前置通知 public void before(){ System.out.println("before.."); } }
3、通知配置
(1)在spring配置文件中开启注解扫描
<?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:util="http://www.springframework.org/schema/util" xmlns:context="http://www.springframework.org/schema/context" 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/util http://www.springframework.org/schema/util/spring-util.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">
(2)使用注解创建User和UserProxy对象
(3)在增强类上加注解@Aspect
(4)在spring配置文件中开启生成代理对象
<!--开启AspectJ代理生产对象--> <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
4、配置不同类型通知
@Component @Aspect //增强类 public class UserProxy { //前置通知 @Before("execution(* org.zhaojianhui.Spring.Bean.User.add(..))") public void before(){ System.out.println("before.."); } }
测试:
public void test() { ApplicationContext appo = new ClassPathXmlApplicationContext("bean2.xml"); //ApplicationContext appo = new AnnotationConfigApplicationContext(SpringConfig.class);;//加载配置类 User user = appo.getBean("user", User.class); user.add(); } }
public class ProxyJDK {
public static void main(String[] args) {
//创建接口实现类代理对象
Class[] interfaces = {UserDao.class};
/* Proxy.newProxyInstance(ProxyJDK.class.getClassLoader(), interfaces, new InvocationHandler() {
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
return null;
}
});*/
UserDaoImpl userDao=new UserDaoImpl();
UserDao dao = (UserDao) Proxy.newProxyInstance(ProxyJDK.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
dao.update();
}
}
//创建代理对象代码
class UserDaoProxy implements InvocationHandler {
//创建的是谁的代理对象,把谁传过来,有参构造器
private Object obj;
public UserDaoProxy(Object obj) {
this.obj = obj;
}
//增强部分
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前
System.out.println("开始增强" + method.getName() + ":传递的参数.." + Arrays.toString(args));
//被增强的方法执行
Object invoke = method.invoke(obj, args);
//方法之后
System.out.println("执行结束" + obj);
return null;
}
}
相同切入点抽取:
//前置通知 @Before(value = "pointCutDemo()") public void before() { System.out.println("before.."); } //相同切入点抽取 @Pointcut(value = "execution(* org.zhaojianhui.Spring.Bean.User.add(..))") public void pointCutDemo() { }
有多个增强类对同一个方法进行增强,设置增强类优先级:在增强类上添加@Order(值)注解,值越小,优先级越高。