AOP术语
1.target:目标类,需要被代理的类。例如:UserService
2.Joinpoint(连接点):所谓连接点是指那些可能被拦截到的方法。例如:所有的方法
3**.PointCut** 切入点:已经被增强的连接点。例如:addUser()
4.advice 通知/增强,增强代码。例如:after、before
5 . Weaving(织入):是指把增强advice应用到目标对象target来创建新的代理对象proxy的过程.
6.proxy 代理类
7 . Aspect(切面): 是切入点pointcut和通知advice的结合,一个切入点和一个通知,组成成一个特殊的面。
cglib
package com.spring.cglb;
//切面类
public class MyAspect {
public void before() {
System.out.println("开启事物");
}
public void after() {
System.out.println("提交事务");
}
}
package com.spring.cglb;
import java.lang.reflect.Method;
import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;
import org.springframework.stereotype.Service;
@Service
public class MyBeanFactory {
public static UserServiceImpl getServiceInstance() {
final MyAspect aspect = new MyAspect();
final UserServiceImpl userService = new UserServiceImpl();
Enhancer e = new Enhancer();
e.setSuperclass(userService.getClass());
//回调函数
e.setCallback(new MethodInterceptor() {
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy proxymethod)
throws Throwable {
aspect.before();
Object obj = method.invoke(userService, args);
aspect.after();
return obj;
}
});
// 创建代理类
UserServiceImpl proxyService = (UserServiceImpl) e.create();
return proxyService;
}
}
AOP联盟通知类型
AOP联盟为通知Advice定义了org.aopalliance.aop.Advice
Spring按照通知Advice在目标类方法的连接点位置,可以分为5类
前置通知 org.springframework.aop.MethodBeforeAdvice
在目标方法执行前实施增强
后置通知 org.springframework.aop.AfterReturningAdvice
在目标方法执行后实施增强
环绕通知 org.aopalliance.intercept.MethodInterceptor
在目标方法执行前后实施增强
异常抛出通知 org.springframework.aop.ThrowsAdvice
在方法抛出异常后实施增强
引介通知 org.springframework.aop.IntroductionInterceptor
在目标类中添加一些新的方法和属性
Aop半自动代理
package com.spring.semiauto;
import org.aopalliance.intercept.MethodInterceptor;
import org.aopalliance.intercept.MethodInvocation;
//切面类 在切面l类中确定通知类型 实现不同的接口 使用环绕通知
public class MyAspect implements MethodInterceptor {
public void before() {
System.out.println("开启事物");
}
public void after() {
System.out.println("提交事务");
}
@Override
public Object invoke(MethodInvocation m) throws Throwable {
this.before();
// 手动执行目标方法
Object obj = m.proceed();
this.after();
return obj;
}
}
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
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">
<!-- target类 -->
<bean id="UserServiceId" class="com.spring.semiauto.UserServiceImpl"></bean>
<!-- 切面类 -->
<bean id="MyAspect" class="com.spring.semiauto.MyAspect"></bean>
<!-- 创建代理类
使用工厂bean FractoryBean,底层调用getObjiect() ,返回bean
proxyFractoryBean 用于创建代理工厂 生成特殊代理对象
interfaces 确定代理的接口们
target 注入目标类
interceptorNames 切面类名称
optimize :强制使用cglib
底层的原理是:
判断有没有接口 有接口使用jdk代理
没有接口使用cglib代理
声明optimize 使用cglib
-->
<bean id="proxyService" class="org.springframework.aop.framework.ProxyFactoryBean" >
<property name="interfaces" value="com.spring.semiauto.UserService"></property>
<property name="target" ref="UserServiceId"></property>
<property name="interceptorNames" value="MyAspect"></property>
</bean>
</beans>
AOP自动代理
导入jar包: 切入点表达式jar
引入命名空间
<?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">
<!-- target类 -->
<bean id="UserService" class="com.spring.auto.UserServiceImpl"></bean>
<!-- 切面类 -->
<bean id="MyAspect" class="com.spring.auto.MyAspect"></bean>
<!-- aop编程 -->
<aop:config>
<aop:pointcut expression="execution(* com.spring.auto.UserServiceImpl.*(..))" id="Mypoincut"/>
<aop:advisor advice-ref="MyAspect" pointcut-ref="Mypoincut"/>
</aop:config>
</beans>
AspectJ
aspectj 通知类型
before:前置通知(应用:各种校验)
在方法执行前执行,如果通知抛出异常,阻止方法运行
afterReturning:后置通知(应用:常规数据处理)
方法正常返回后执行,如果方法中抛出异常,通知无法执行
必须在方法执行后才执行,所以可以获得方法的返回值。
around:环绕通知(应用:十分强大,可以做任何事情)
方法执行前后分别执行,可以阻止方法的执行必须手动执行目标方法
afterThrowing:抛出异常通知(应用:包装异常信息)
方法抛出异常后执行,如果方法没有抛出异常,无法执行
after:最终通知(应用:清理现场)
方法执行完毕后执行,无论方法中是否出现异常
aspectj编程
package com.spring.aspectj;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
//切面类
public class MyAspect {
public void before(JoinPoint jp) {
String name = jp.getSignature().getName();
System.out.println("前置通知:" + "方法名。。。。" + name);
}
public void afterReturning(JoinPoint jp, Object ret) {
System.out.println("后置通知");
System.out.println(ret);
}
public void after(JoinPoint jp) {
String name = jp.getSignature().getName();
System.out.println("最终通知:" + "方法名。。。。" + name);
}
public Object MyArround(ProceedingJoinPoint pjp, Object ret) throws Throwable {
this.before(pjp);
Object object = pjp.proceed();
this.afterReturning(pjp, ret);
return object;
}
public void MyAfterThrowable(JoinPoint jp, Throwable e) {
String name = jp.getSignature().getName();
System.out.println("异常:" + name + "..." + e.getMessage());
}
}
<?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="UserService" class="com.spring.aspectj.UserServiceImpl"></bean>
<!-- 切面类 -->
<bean id="MyAspect" class="com.spring.aspectj.MyAspect"></bean>
<!-- 前置通知配置 ref 引入切面 pointcut 切入点表达式 此表达式只能当前通知使用 pointcut 切入点引用 可与其他通知共享 -->
<aop:config>
<aop:aspect ref="MyAspect">
<aop:pointcut
expression="execution(*
com.spring.aspectj.UserServiceImpl.*(..))"
id="Mypointcut" />
<aop:before method="before" pointcut-ref="Mypointcut" />
</aop:aspect>
</aop:config>
<!-- 最终通知 -->
<aop:config>
<aop:aspect ref="MyAspect">
<aop:pointcut
expression="execution(*
com.spring.aspectj.UserServiceImpl.*(..))"
id="Mypointcut" />
<aop:after method="after" pointcut-ref="Mypointcut" />
</aop:aspect>
</aop:config>
<!-- 环绕通知 -->
<aop:config>
<aop:aspect ref="MyAspect">
<aop:pointcut expression="execution(* com.spring.aspectj.UserServiceImpl.*(..))"
id="Mypointcut" />
<aop:around method="MyArround" pointcut-ref="Mypointcut" />
</aop:aspect>
</aop:config>
<!-- 异常通知 -->
<aop:config>
<aop:aspect ref="MyAspect">
<aop:pointcut expression="execution(* com.spring.aspectj.UserServiceImpl.*(..))"
id="Mypointcut" />
<aop:after-throwing method="MyAfterThrowable"
pointcut-ref="Mypointcut" throwing="e" />
</aop:aspect>
</aop:config>
<!-- 后置通知 -->
<aop:config>
<aop:aspect ref="MyAspect">
<aop:pointcut expression="execution(* com.spring.aspectj.UserServiceImpl.*(..))"
id="Mypointcut" />
<aop:after-returning method="afterReturning"
pointcut-ref="Mypointcut" returning="ret" />
</aop:aspect>
</aop:config>
</beans>
使用注解
//切面类
@Component
@Aspect
public class MyAspect {
//创建切入点表达式
@Pointcut("execution(* com.spring.aop_annotation.UserServiceImpl.*(..))")
public void MyPointCut() {
}
@Before("MyPointCut()")
public void before(JoinPoint jp) {
String name = jp.getSignature().getName();
System.out.println("前置通知:" + "方法名。。。。" + name);
}
@AfterReturning(value = "MyPointCut()", returning = "ret")
public void afterReturning(JoinPoint jp, Object ret) {
System.out.println("后置通知");
System.out.println(ret);
}
@After("MyPointCut()")
public void after(JoinPoint jp) {
String name = jp.getSignature().getName();
System.out.println("最终通知:" + "方法名。。。。" + name);
}
@Around("MyPointCut()")
public Object MyArround(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("前");
Object object = pjp.proceed();
System.out.println("后");
return object;
}
@AfterThrowing(value = "MyPointCut()", throwing = "e")
public void MyAfterThrowable(JoinPoint jp, Throwable e) {
String name = jp.getSignature().getName();
System.out.println("异常:" + name + "..." + e.getMessage());
}
}
<?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"
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/aop
http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context
http://www.springframework.org/schema/context/spring-context.xsd">
<context:component-scan base-package="com.spring.aop_annotation"></context:component-scan>
<!-- 使aop注解生效 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>