AOP,Aspect Oriented Programming,面向切面编程,是对面向对象编程OOP的升华。OOP是纵向对一个事物的抽象,一个对象包括静态的属性信息,包括动态的方法信息等。而AOP是横向的对不同事物的抽象,属性与属性、方法与方法、对象与对象都可以组成一个切面,而用这种思维去设计编程的方式叫做面向切面编程。
动态代理技术,在运行期间,对目标对象的方法进行增强,代理对象同名方法内可以执行原有逻辑的同时嵌入执行其他增强逻辑或其他对象的方法。
学习BeanPostProcessor时,在BeanPostProcessor的after方法中使用动态代理对Bean进行了增强,实际存储到单例池singleObjects中的不是当前目标对象本身,而是当前目标对象的代理对象Proxy,这样在调用目标对象方法时,实际调用的是代理对象Proxy的同名方法,起到了目标方法前后都进行增强的功能,对该方式进行一下优化,将增强的方法提取出去到一个增强类中,且只对com.zgs.service.impl包下的任何类的任何方法进行增强。
SpringConfig
@Configuration
@ComponentScan(basePackages = "com.zgs")
public class SpringConfig {
}
ApplicationContextTest
public class ApplicationContextTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
userService.show1();
}
}
MyAdvice
@Component
public class MyAdvice {
public void before() {
System.out.println("MyAdvice的before方法执行.....");
}
public void after() {
System.out.println("MyAdvice的after方法执行.....");
}
}
MockAopBeanPostProcessor
@Component
public class MockAopBeanPostProcessor implements BeanPostProcessor, ApplicationContextAware {
private ApplicationContext applicationContext;
@Override
public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
if (bean.getClass().getPackage().getName().equals("com.zgs.service.impl")) {
//对bean进行动态代理增强-生成bean的代理类
Object proxyBean = Proxy.newProxyInstance(bean.getClass().getClassLoader(),
bean.getClass().getInterfaces(),
(Object proxy, Method method, Object[] args) -> {
//拦截目标方法,调用目标方法,并做增强
//前置增强
MyAdvice myAdvice = applicationContext.getBean(MyAdvice.class);
myAdvice.before();
//调用目标方法
Object obj = method.invoke(bean, args);
//调用后置增强
myAdvice.after();
return obj;
});
return proxyBean;
}
return bean;
}
@Override
public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
this.applicationContext = applicationContext;
}
}
UserService
public interface UserService {
void show1();
void show2();
}
UserServiceImpl
@Component
public class UserServiceImpl implements UserService {
@Override
public void show1() {
System.out.println("UserServiceImpl的show1方法执行");
}
@Override
public void show2() {
System.out.println("UserServiceImpl的show2方法执行");
}
}
<?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: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
https://www.springframework.org/schema/context/spring-context.xsd">
<bean id="userService" class="com.zgs.service.impl.UserServiceImpl"></bean>
<bean id="userDao" class="com.zgs.dao.impl.UserDaoImpl"></bean>
<bean id="myAdvice" class="com.zgs.advice.MyAdvice"></bean>
<bean id="mockAopBeanPostProcessor" class="com.zgs.post.MockAopBeanPostProcessor"></bean>
</beans>
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.9.6</version>
</dependency>
<?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: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/context
https://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="userService" class="com.zgs.service.impl.UserServiceImpl"></bean>
<!--通知类-->
<bean id="myAdvice" class="com.zgs.advice.MyAdvice"></bean>
<!--aop配置-->
<aop:config>
<!--配置切点表达式 目的知道那些方法需要被增强-->
<aop:pointcut id="myPointCut" expression="execution(void com.zgs.service.impl.UserServiceImpl.show1())"/>
<aop:pointcut id="myPointCut2" expression="execution(void com.zgs.service.impl.UserServiceImpl.show2())"/>
<!--配置织入 目的知道那些方法需要被增强-->
<aop:aspect ref="myAdvice">
<aop:before method="beforeAdvice" pointcut-ref="myPointCut"/>
<aop:after method="afterAdvice" pointcut-ref="myPointCut"/>
<aop:before method="beforeAdvice" pointcut-ref="myPointCut2"/>
<aop:after method="afterAdvice" pointcut="execution(void com.zgs.service.impl.UserServiceImpl.show2())"/>
</aop:aspect>
</aop:config>
<!-- <bean id="userDao" class="com.zgs.dao.impl.UserDaoImpl"></bean>-->
<!-- <bean id="mockAopBeanPostProcessor" class="com.zgs.post.MockAopBeanPostProcessor"></bean>-->
</beans>
ApplicationContextTest
public class ApplicationContextTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
userService.show1();
userService.show2();
}
}
MyAdvice
@Component
public class MyAdvice {
public void beforeAdvice() {
System.out.println("MyAdvice的before增强方法执行.....");
}
public void afterAdvice() {
System.out.println("MyAdvice的after增强方法执行.....");
}
}
直接将切点表达式配置在通知上,
也可以将切点表达式抽取到外面,在通知上进行引用
execution([访问修饰符]返回值类型 包名.类名.方法名(参数))
//表示访问修饰符为public、无返回值、在com.zgs.aop包下的TargetImpl类的无参方法show
execution(public void com.zgs.aop.TargetImpl.show())
//表述com.zgs.aop包下的TargetImpl类的任意方法
execution(* com.zgs.aop.TargetImpl.*(..))
//表示com.zgs.aop包下的任意类的任意方法
execution(* com.zgs.aop.*.*(..))
//表示com.zgs.aop包及其子包下的任意类的任意方法
execution(* com.zgs.aop..*.*(..))
//表示任意包中的任意类的任意方法
execution(* *..*.*(..))
public void 通知方法名称(JoinPoint joinPoint){
//获得目标方法的参数
System.out.println(joinPoint.getArgs());
//获得目标对象
System.out.println(joinPoint.getTarget());
//获得精确的切点表达式信息
System.out.println(joinPoint.getStaticPart());
}
public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println(joinPoint.getArgs());//获得目标方法的参数
System.out.println(joinPoint.getTarget());//获得目标对象
System.out.println(joinPoint.getStaticPart());//获得精确的切点表达式信息
Object result = joinPoint.proceed();//执行目标方法
return result;//返回目标方法返回值
}
public void afterThrowing(JoinPoint joinPoint,Throwable th){
//获得异常信息
System.out.println("异常对象是:"+th+"异常信息是:"+th.getMessage());
}
ApplicationContextTest
public class ApplicationContextTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
userService.show1();
System.out.println("========================================");
userService.show2();
}
}
UserServiceImpl
@Component
public class UserServiceImpl implements UserService {
@Override
public void show1() {
System.out.println("UserServiceImpl的show1方法执行");
}
@Override
public void show2() {
System.out.println("UserServiceImpl的show2方法执行");
//模拟抛出异常
int i = 1 / 0;
}
}
MyAdvice
@Component
public class MyAdvice {
// public void beforeAdvice() {
// System.out.println("前置通知---MyAdvice的before增强方法执行.....");
// }
public void beforeAdvice(JoinPoint joinPoint) {
System.out.println("当前目标对象---"+joinPoint.getTarget());
System.out.println("当前目标方法---"+joinPoint.getSignature().getName());
System.out.println("当前表达式---"+joinPoint.getStaticPart());
System.out.println("前置通知带参数---MyAdvice的before增强方法执行.....");
}
public void afterAdvice() {
System.out.println("最终通知---MyAdvice的after增强方法执行.....");
}
public void afterReturnAdvice() {
System.out.println("后置通知---MyAdvice的afterReturn增强方法执行.....");
}
public void aroundAdvice(ProceedingJoinPoint joinPoint) throws Throwable {
System.out.println("环绕前通知---MyAdvice的around增强方法执行.....");
//执行目标方法
Object proceed = joinPoint.proceed();
System.out.println("环绕后通知---MyAdvice的around增强方法执行.....");
}
public void afterThrowingAdvice(Throwable throwable) {
System.out.println("当前异常---"+throwable);
System.out.println("异常通知---MyAdvice的afterThrowingAdvice增强方法执行.....");
}
}
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: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/context
https://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="userService" class="com.zgs.service.impl.UserServiceImpl"></bean>
<!--通知类-->
<bean id="myAdvice" class="com.zgs.advice.MyAdvice"></bean>
<!--aop配置-->
<aop:config>
<!--配置切点表达式 目的知道那些方法需要被增强-->
<!-- <aop:pointcut id="myPointCut" expression="execution(void com.zgs.service.impl.UserServiceImpl.show1())"/>-->
<!-- <aop:pointcut id="myPointCut2" expression="execution(void com.zgs.service.impl.UserServiceImpl.show2())"/>-->
<aop:pointcut id="myPointCut2" expression="execution(* com.zgs.service.impl.*.*(..))"/>
<!--配置织入 目的知道那些方法需要被增强-->
<aop:aspect ref="myAdvice">
<!-- <aop:before method="beforeAdvice" pointcut-ref="myPointCut"/>-->
<!-- <aop:after method="afterAdvice" pointcut-ref="myPointCut"/>-->
<aop:before method="beforeAdvice" pointcut-ref="myPointCut2"/>
<!-- <aop:after-returning method="afterReturnAdvice" pointcut-ref="myPointCut2"/>-->
<!-- <aop:around method="aroundAdvice" pointcut-ref="myPointCut2"/>-->
<aop:after-throwing method="afterThrowingAdvice" pointcut-ref="myPointCut2" throwing="throwable"/>
<aop:after method="afterAdvice" pointcut-ref="myPointCut2"/>
</aop:aspect>
</aop:config>
<!-- <bean id="userDao" class="com.zgs.dao.impl.UserDaoImpl"></bean>-->
<!-- <bean id="mockAopBeanPostProcessor" class="com.zgs.post.MockAopBeanPostProcessor"></bean>-->
</beans>
ApplicationContextTest
public class ApplicationContextTest {
public static void main(String[] args) {
ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicationContext.xml");
// ApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class);
UserService userService = applicationContext.getBean(UserService.class);
userService.show1();
System.out.println("========================================");
userService.show2();
}
}
UserServiceImpl
@Component
public class UserServiceImpl implements UserService {
@Override
public void show1() {
System.out.println("UserServiceImpl的show1方法执行");
}
@Override
public void show2() {
System.out.println("UserServiceImpl的show2方法执行");
//模拟抛出异常
}
}
MyAdvice2
@Component
public class MyAdvice2 implements MethodBeforeAdvice, AfterReturningAdvice {
@Override
public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
System.out.println("最终通知。。。。。。。。。。。");
}
@Override
public void before(Method method, Object[] args, Object target) throws Throwable {
System.out.println("前置通知。。。。。。。。。。。");
}
}
MyAdvice3
@Component
public class MyAdvice3 implements MethodInterceptor {
@Override
public Object invoke(MethodInvocation invocation) throws Throwable {
System.out.println("环绕前通知。。。。。。。。。。。。。。。。。。");
Object invoke = invocation.getMethod().invoke(invocation.getThis(), invocation.getArguments());
System.out.println("环绕后通知。。。。。。。。。。。。。。。。。。");
return invoke;
}
}
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: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/context
https://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="userService" class="com.zgs.service.impl.UserServiceImpl"></bean>
<!--通知类-->
<bean id="myAdvice" class="com.zgs.advice.MyAdvice"></bean>
<!--通知类-->
<bean id="myAdvice2" class="com.zgs.advice.MyAdvice2"></bean>
<!--通知类-->
<bean id="myAdvice3" class="com.zgs.advice.MyAdvice3"></bean>
<!--aop配置-->
<aop:config>
<!--配置切点表达式 目的知道那些方法需要被增强-->
<!-- <aop:pointcut id="myPointCut" expression="execution(void com.zgs.service.impl.UserServiceImpl.show1())"/>-->
<!-- <aop:pointcut id="myPointCut2" expression="execution(void com.zgs.service.impl.UserServiceImpl.show2())"/>-->
<aop:pointcut id="myPointCut2" expression="execution(* com.zgs.service.impl.*.*(..))"/>
<!--配置织入 目的知道那些方法需要被增强-->
<!-- <aop:aspect ref="myAdvice">-->
<!-- <!– <aop:before method="beforeAdvice" pointcut-ref="myPointCut"/>–>-->
<!-- <!– <aop:after method="afterAdvice" pointcut-ref="myPointCut"/>–>-->
<!-- <!– <aop:before method="beforeAdvice" pointcut-ref="myPointCut2"/>–>-->
<!-- <!– <aop:after-returning method="afterReturnAdvice" pointcut-ref="myPointCut2"/>–>-->
<!-- <!– <aop:around method="aroundAdvice" pointcut-ref="myPointCut2"/>–>-->
<!-- <!– <aop:after-throwing method="afterThrowingAdvice" pointcut-ref="myPointCut2" throwing="throwable"/>–>-->
<!-- <!– <aop:after method="afterAdvice" pointcut-ref="myPointCut2"/>–>-->
<!-- </aop:aspect>-->
<aop:advisor advice-ref="myAdvice2" pointcut-ref="myPointCut2"/>
<aop:advisor advice-ref="myAdvice3" pointcut-ref="myPointCut2"/>
</aop:config>
<!-- <bean id="userDao" class="com.zgs.dao.impl.UserDaoImpl"></bean>-->
<!-- <bean id="mockAopBeanPostProcessor" class="com.zgs.post.MockAopBeanPostProcessor"></bean>-->
</beans>
输出结果
http\://www.springframework.org/schema/aop=org.springframework.aop.config.AopNamespaceHandler
详情见流程图。
<aop:config proxy-target-class="true">
<!--配置切点表达式 目的知道那些方法需要被增强-->
<!-- <aop:pointcut id="myPointCut" expression="execution(void com.zgs.service.impl.UserServiceImpl.show1())"/>-->
<!-- <aop:pointcut id="myPointCut2" expression="execution(void com.zgs.service.impl.UserServiceImpl.show2())"/>-->
<aop:pointcut id="myPointCut2" expression="execution(* com.zgs.service.impl.*.*(..))"/>
<!--配置织入 目的知道那些方法需要被增强-->
<aop:aspect ref="myAdvice">
<!-- <aop:before method="beforeAdvice" pointcut-ref="myPointCut"/>-->
<!-- <aop:after method="afterAdvice" pointcut-ref="myPointCut"/>-->
<aop:before method="beforeAdvice" pointcut-ref="myPointCut2"/>
<aop:after-returning method="afterReturnAdvice" pointcut-ref="myPointCut2"/>
<aop:around method="aroundAdvice" pointcut-ref="myPointCut2"/>
<aop:after-throwing method="afterThrowingAdvice" pointcut-ref="myPointCut2" throwing="throwable"/>
<aop:after method="afterAdvice" pointcut-ref="myPointCut2"/>
</aop:aspect>
<!-- <aop:advisor advice-ref="myAdvice2" pointcut-ref="myPointCut2"/>-->
<!-- <aop:advisor advice-ref="myAdvice3" pointcut-ref="myPointCut2"/>-->
</aop:config>
输出结果
CGlibTest
public class CGlibTest {
public static void main(String[] args) {
//目标对象
Target target = new Target();
//通知对象
MyAdvice4 myAdvice4 = new MyAdvice4();
//编写cglib代码
Enhancer enhancer = new Enhancer();
//设置父类
enhancer.setSuperclass(Target.class);
//设置回调
enhancer.setCallback(new MethodInterceptor() {
@Override
//相当于jdk的proxy的invkoe方法
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
myAdvice4.before();
Object result = methodProxy.invoke(target, objects);
myAdvice4.after();
return result;
}
});
//生成代理对象
Target proxy = (Target) enhancer.create();
proxy.show();
}
}
Target
public class Target {
public void show(){
System.out.println("Target.show()");
}
}
MyAdvice4
@Component
public class MyAdvice4 {
public void before() {
System.out.println("前置增强");
}
public void after() {
System.out.println("后置增强");
}
}
输出结果