Spring IOC容器、Spring Bean的生命周期、Spring Aop

一、Spring IOC容器初始化过程

Ioc容器是一个Map集合 (可以通过getBean()方法获取到对应key的value,value存放的是对象)。这边引用一下整体流程图片

 ①自定义bean的xml文件 (比如数据库的配置)

<!--bean信息如下所示-->
<context:property-placeholder location="dbconfig.properties"/>
<bean>
    <!--属性填充,value用占位符,并没有真正的赋值-->
    <property name="username" value="${jdbc.username}"/>
    <property name="password" value="${jdbc.password}"/>
    <property name="driverClassName" value="${jdbc.driverclass}"/>
    <property name="url" value="${jdbc.url}"/>
</bean>

②通过BeanDefinitionReader读取bean文件成为BeanDefinition对象,${}占位符并没有真正获取。

 ③XmlBeanDefinitionReader的实现方法

//XmlBeanDefinitionReader调用的是父类AbstractBeanDefinitionReader构造方法
public XmlBeanDefinitionReader(BeanDefinitionRegistry registry) {
    super(registry);
}


//父类AbstractBeanDefinitionReader的构造方法如下
protected AbstractBeanDefinitionReader(BeanDefinitionRegistry registry) {
    //先断言registry非空
    Assert.notNull(registry, "BeanDefinitionRegistry must not be null");
    this.registry = registry;

    // instance of判断registry是否是ResourceLoader的子类
    if (this.registry instanceof ResourceLoader) {
        this.resourceLoader = (ResourceLoader) this.registry;
    }
    else {
        this.resourceLoader = new PathMatchingResourcePatternResolver();
    }

    // instance of判断registry是否是EnvironmentCapable的子类
    if (this.registry instanceof EnvironmentCapable) {
        this.environment = ((EnvironmentCapable) this.registry.getEnvironment();
    }
    else {
        this.environment = new StandardEnvironment();
    }
}

④BeanDefinition所包含的内容

下图就是beanDefinition所包含的内容。看到这些属性如果对Spring有所了解都应该知道几个,如lazyInit懒加载,在Spring中有一个@Lazy注解,用来标识其这个bean是否为懒加载的,scope属性,相应的也有@scope注解来标识这个bean其作用域,是单例还是多例,beanClass属性,在对象实例化时,会根据beanClass来创建对象、又比如autowireMode注入模型这个属性,这个属性用于记录使用怎样的注入模型,注入模型常用的有根据名称和根据类型、不注入三种注入模型等。

 ⑤BeanDefinition接口定义了大量的常量和方法,具体如下

public interface BeanDefinition extends AttributeAccessor, BeanMetadataElement {

	// 常量标志一个bean的作用范围
	String SCOPE_SINGLETON = ConfigurableBeanFactory.SCOPE_SINGLETON;
	String SCOPE_PROTOTYPE = ConfigurableBeanFactory.SCOPE_PROTOTYPE;

    // 设置父BeanDefinition,可以只对有父子关系的bean
	void setParentName(@Nullable String parentName);
	String getParentName();
    // bean的类的全限定名
	void setBeanClassName(@Nullable String beanClassName);
	String getBeanClassName();

	void setScope(@Nullable String scope);
	String getScope();

	void setLazyInit(boolean lazyInit);
	boolean isLazyInit();

    // 设置依赖性,被依赖的bean会优先创建
	void setDependsOn(@Nullable String... dependsOn);
	String[] getDependsOn();
	// 是否允许自动装配
	void setAutowireCandidate(boolean autowireCandidate);
	boolean isAutowireCandidate();

    // 设置是否主要bean
	void setPrimary(boolean primary);
	boolean isPrimary();

	// 工厂bean和工厂方法
	void setFactoryBeanName(@Nullable String factoryBeanName);
	String getFactoryBeanName();
	void setFactoryMethodName(@Nullable String factoryMethodName);
	String getFactoryMethodName();

	ConstructorArgumentValues getConstructorArgumentValues();
	default boolean hasConstructorArgumentValues() {
		return !getConstructorArgumentValues().isEmpty();
	}


    // 使用setter注入时的key-value对,都保存在这里
	MutablePropertyValues getPropertyValues();
	default boolean hasPropertyValues() {
		return !getPropertyValues().isEmpty();
	}

	// @since 5.1初始化方法和销毁方法
	void setInitMethodName(@Nullable String initMethodName);
	String getInitMethodName();
	void setDestroyMethodName(@Nullable String destroyMethodName);
	String getDestroyMethodName();

	// 为bean设置角色
	void setRole(int role);
	int getRole();

	// bean的描述
	void setDescription(@Nullable String description);
	String getDescription();

	// 返回此bean定义的可解析类型,基于bean类或其他特定元数据。
    // 这通常在运行时合并bean定义上完全解决但不一定是在配置时定义实例上。
	ResolvableType getResolvableType();
	boolean isSingleton();
	boolean isPrototype();
	boolean isAbstract();
}

⑥Java类 ---> BeanDefinition类的代码

//************AbstractBeanDefinition类*********************
public abstract class AbstractBeanDefinition extends BeanMetadataAttributeAccessor
		implements BeanDefinition, Cloneable {

	// 定义一些常量
	public static final String SCOPE_DEFAULT = "";
	public static final int AUTOWIRE_NO = AutowireCapableBeanFactory.AUTOWIRE_NO;
	public static final int AUTOWIRE_BY_NAME = AutowireCapableBeanFactory.AUTOWIRE_BY_NAME;
	public static final int AUTOWIRE_BY_TYPE = AutowireCapableBeanFactory.AUTOWIRE_BY_TYPE;
    // ...还有很多

	// 初始化默认值
	private volatile Object beanClass;
	private String scope = SCOPE_DEFAULT
	private boolean autowireCandidate = true;
	private boolean primary = false;
	// ...还有很多

	// 构造器
	protected AbstractBeanDefinition() {
		this(null, null);
	}

	// 指定构造器参数和属性参数
	protected AbstractBeanDefinition(@Nullable ConstructorArgumentValues cargs, @Nullable MutablePropertyValues pvs) {
		this.constructorArgumentValues = cargs;
		this.propertyValues = pvs;
	}

	// 使用深拷贝创建一个新的
	protected AbstractBeanDefinition(BeanDefinition original) {
		
	}


	// 复制一个bean的定义到当前bean,通常父子bean合并时可用
	public void overrideFrom(BeanDefinition other) {
		
	}

	// ...此处省略其他的方法实现
}



//*******************GenericBeanDefinition类*********************
public class GenericBeanDefinition extends AbstractBeanDefinition {

   @Nullable
   private String parentName;

   public GenericBeanDefinition() {
      super();
   }

   // 通过深拷贝创建一个bean
   public GenericBeanDefinition(BeanDefinition original) {
      super(original);
   }

   @Override
   public void setParentName(@Nullable String parentName) {
      this.parentName = parentName;
   }

   @Override
   @Nullable
   public String getParentName() {
      return this.parentName;
   }

   @Override
   public AbstractBeanDefinition cloneBeanDefinition() {
      return new GenericBeanDefinition(this);
   }
}

//测试
@Test
public void testGenericBeanDefinition(){
    GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
    beanDefinition.setBeanClassName("com.ydlclass.User");
    // 此处类似setter注入的描述
    MutablePropertyValues propertyValues = new MutablePropertyValues();
    propertyValues.addPropertyValue("name","lily");
    propertyValues.addPropertyValue("age",12);
    beanDefinition.setPropertyValues(propertyValues);
}

⑦在这里Spring为我们提供了一个扩展的切口,允许我们通过实现接口BeanFactoryPostProcessor 在此处来插入我们定义的代码。后置处理器BeanFactoryPostProcessor还完成了@Bean、@Component等注解解析,这个后置处理器可以将${xxx}占位符替换为实际的字符串值。典型的例子就是:PropertyPlaceholderConfigurer,我们一般在配置数据库的dataSource时使用到的占位符的值,就是它注入进去的。

public abstract class PropertyResourceConfigurer extends PropertiesLoaderSupport
        implements BeanFactoryPostProcessor, PriorityOrdered {
    @Override
    public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws     
        BeansException {
        try {
            Properties mergedProps = mergeProperties();
            // Convert the merged properties, if necessary.
            convertProperties(mergedProps);
            // Let the subclass process the properties.
            processProperties(beanFactory, mergedProps);
        }
        catch (IOException ex) {
            throw new BeanInitializationException("Could not load properties", ex);
        }
    }
}

⑧然后通过BeanDefinitionRegistry将这些BeanDefinition对象注册到beanFactory容器中。

@SuppressWarnings("serial")
public class DefaultListableBeanFactory extends AbstractAutowireCapableBeanFactory
        implements ConfigurableListableBeanFactory, BeanDefinitionRegistry, Serializable {
    /** Map of bean definition objects, keyed by bean name */
    private final Map<String, BeanDefinition> beanDefinitionMap = new 
                 ConcurrentHashMap<String, BeanDefinition>(64);
    
    @Override
    public void registerBeanDefinition(String beanName, BeanDefinition beanDefinition)
            throws BeanDefinitionStoreException {
        // ... ...
       this.beanDefinitionMap.put(beanName, beanDefinition);
       // ... ...
    }
}

⑨Spring IOC容器的最后说明:Spring提供IOC容器实现两种方式(两个接口):BeanFactory和ApplicationContext。

>BeanFactory:

        >>IOC容器基本实现,是Spring内部的使用接口,不提供开发人员进行使用

        >>加载配置文件Xml的时候不会创建对象,在获取对象的时候才去创建对象

>ApplicationContext:

        >>BeanFactory接口的子接口,提供更多更强大的功能,一般由开发人员使用 ​

        >>加载配置文件Xml的时候就会把在配置文件对象进行创建

二、Spring Bean的生命周期

我们知道一般的对象生命周期是这样的:先通过new关键字将对象实例化到堆中,然后就可以使用Java对象了,不再使用对象之后通过JVM垃圾回收销毁。但是Spring Bean的生命周期不是这样,具体步骤如下所示:Bean实例化-->Bean属性赋值-->初始化-->销毁这四个阶段。

 ①上述是Bean本身的方法,加上IOC容器的生命周期(BeanPostProcessor 一系列接口)

② InstantiationAwareBeanPostProcessor 是继承了 BeanPostProcessor 

//InstantiationAwareBeanPostProcessor接口的定义
public interface InstantiationAwareBeanPostProcessor extends BeanPostProcessor {

    @Nullable
    default 0bject postProcessBeforeInstantiation(Class<?> beanClass,String beanName)             
    throws BeansException {
        return null;
    }


    default 0bject postProcessBeforeInstantiation(Class<?> beanClass,String beanName)         
    throws BeansException {
        return true;
    }


    @Nullable
    default 0bject postProcessBeforeInstantiation(Class<?> beanClass,String beanName)     
    throws BeansException {
        return null;
    }

    @Deprecated
    @Nullable
    default 0bject postProcessBeforeInstantiation(Class<?> beanClass,String beanName)     
    throws BeansException {
        return pvs;
    }
}

//BeanPostProcessor接口的定义
public interface BeanPostProcessor {
    @Nullable
    default 0bject postProcessBeforeInitialization(Object bean,String beanName) throws     
    BeansException {
        return bean;
    }

    @Nullable
    default 0bject postProcessAfterInitialization(Object bean,String beanName) throws     
    BeansException {
        return bean;
    }
}

③InstantiationAwareBeanPostProcessor接口中的方法介绍

方法描述
postProcessBeforeInitializationBeanPostProcessor接口中的方法,在Bean的自定义初始化方法之前执行
postProcessAfterInitializationBeanPostProcessor接口中的方法,在Bean的自定义初始化方法之后执行
postProcessBeforeInstantiation自身方法,是最先执行的方法,它在目标对象实例化之前调用,该方法的返回值类型是Object,我们可以返回任何类型的值。由于这个时候目标对象还未实例化,所以这个返回值可以用来代替原本该生成的目标对象的实例(比如代理对象)。如果该方法的返回值代替原本该生成的目标对象,后续只有postProcessAfterInitialization方法会调用,其它方法不再调用;否则按照
按照正常的流程走
postProcessAfterInstantiation目标对象实例化之后调用,这个时候对象已经被实例化,但是该实例的属性还未被设置,都是null。因为它的返回值是决定要不要调用postProcessPropertyValues方法的其中一个因素(因为还有一个因素是mbd.getDependencyCheck());如果该方法返回false,并且不需要check,那么postProcessPropertyValues就会被忽略不执行;如果返回true,postProcessPropertyValues就会被执行
postProcessPropertyValues对属性值进行修改,如果postProcessAfterInstantiation方法返回false,该方法可能不会被调用。可以在该方法内对属性值进行修改

④Bean级生命周期的方法之一(Aware类型的接口):让我们能够拿到 Spring 容器中的一些资源。

因为 Aware 方法都是执行在初始化方法之前,所以可以在初始化方法中放心大胆的使用 Aware 接口获取的资源,这也是我们自定义扩展 Spring 的常用方式。

方法描述
BeanNameAware需要实现setBeanName()方法,这个方法只是简单的返回我们当前的beanName, 知道自己在spring容器里的名字
BeanClasLoaderAware获取Bean的类装载器
BeanFactoryAware获取Bean的工厂
EnviromentAware可以获得application.properties的配置文件配置的属性值
EmbeddedValueResolverAware基于Spring解析获取properties文件的单个属性值
ApplicationContextAware/ResourceLoaderAwareApplicationContextAware接口会自动的将程序上下文加入

⑤Bean级生命周期方法之二(生命周期类型接口):自己实现的有初始化和销毁两个生命周期阶段。spring初始化bean的时候,如果bean实现了InitializingBean接口,会自动调用afterPropertiesSet方法,在bean被销毁的时候如果实现了DisposableBean接口会自动回调destroy方法后然后再销毁。

方法描述
InitializingBean对应生命周期的初始化阶段。InitializingBean接口为bean提供了初始化方法的方式,它只包括afterPropertiesSet方法,凡是继承该接口的类,在初始化bean的时候都会执行该方法
DisposableBean类似InitializingBean,对应生命周期销毁阶段。允许在容器销毁该bean的时候获得一次回调

⑥Spring Bean生命周期流程图

 三、代码演示

①UserBean类

//UserBean类的定义、继承接口InitializingBean/BeanNameAware/DisposableBean
@Component
public class UserBean implements InitializingBean, BeanNameAware, DisposableBean, ApplicationContextAware {
	private int id;//id属性
	private String name;//name属性

    //UserBean构造器
	public UserBean(int id, String name) {
		this.id = id;
		this.name = name;
		System.out.println("2. 调用构造函数");
	}

	public int getId() {
		return id;
	}

	public void setId(int id) {
		this.id = id;
		System.out.println("5. 属性注入 id");
	}

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
		System.out.println("5. 属性注入 name");
	}

    //实现接口BeanNameAware的setBeanName方法
	@Override
	public void setBeanName(String name) {
		System.out.println("6. 调用 BeanNameAware.setBeanName() 方法");
	}

    //实现方法setApplicationContext
	@Override
	public void setApplicationContext(ApplicationContext applicationContext) throws         
    BeansException {
		UserBean userBean = (UserBean) applicationContext.getBean("userBean");
		System.out.println(userBean);
		System.out.println("7. 调用 BeanNameAware.setBeanName() 方法");
	}

    //实现方法afterPropertiesSet()
	@Override
	public void afterPropertiesSet() throws Exception {
		System.out.println("9. 调用 InitializingBean.afterPropertiesSet() 方法");
	}

    //初始化方法
	public void myInit() {
		System.out.println("10. 调用 init-method 方法");
	}

    //实现DisposableBean的destroy销毁方法
	@Override
	public void destroy() throws Exception {
		System.out.println("12. 调用 DisposableBean.destroy() 方法");
	}

    //销毁方法
	public void myDestroy() {
		System.out.println("13. 调用 destroy-method 方法");
	}

    //toString()方法打印对象
	@Override
	public String toString() {
		return "UserBean{" +
				"id=" + id +
				", name='" + name + '\'' +
				'}';
	}
}

②InstantiationAwareBeanPostProcessor 接口实现类

@Component
public class MyInstantiationAwareBeanPostProcessor implements InstantiationAwareBeanPostProcessor {
	@Override
	public Object postProcessBeforeInstantiation(Class<?> beanClass, String beanName) throws BeansException {
		if ("userBean".equals(beanName)) {
			System.out.println("1. 调用 InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation() 方法");
		}
		return null;
	}

	@Override
	public boolean postProcessAfterInstantiation(Object bean, String beanName) throws BeansException {
		if ("userBean".equals(beanName)) {
			UserBean userBean = (UserBean) bean;
			System.out.println("3. 调用 InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation() 方法");
			System.out.println(userBean);
		}
		return true;
	}

	@Override
	public PropertyValues postProcessProperties(PropertyValues pvs, Object bean, String beanName) throws BeansException {
		if ("userBean".equals(beanName)) {
			System.out.println("4. 调用 InstantiationAwareBeanPostProcessor.postProcessProperties() 方法");
		}
		return null;
	}
}

③BeanPostProcessor 接口实现类

@Component
public class MyBeanPostProcessor implements BeanPostProcessor {
	@Override
	public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
		if ("userBean".equals(beanName)) {
			System.out.println("8. 调用 BeanPostProcessor.postProcessBeforeInitialization() 方法");
		}
		return bean;
	}

	@Override
	public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
		if ("userBean".equals(beanName)) {
			System.out.println("11. 调用 BeanPostProcessor.postProcessAfterInitialization() 方法");
		}
		return bean;
	}
}

④BeanFactoryPostProcessor 接口实现类

@Component
public class MyBeanFactoryPostProcessor implements BeanFactoryPostProcessor {
	@Override
	public void postProcessBeanFactory(ConfigurableListableBeanFactory beanFactory) throws BeansException {
		System.out.println("0. 调用 BeanFactoryPostProcessor.postProcessBeanFactory() 方法");
	}
}

⑤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"
	   xsi:schemaLocation="
	    http://www.springframework.org/schema/beans
        https://www.springframework.org/schema/beans/spring-beans.xsd
">

	<bean class="com.riemann.test.MyInstantiationAwareBeanPostProcessor" />

	<bean id="userBean" class="com.riemann.test.UserBean" init-method="myInit" destroy-method="myDestroy">
		<!-- 构造函数注入 -->
		<constructor-arg index="0" type="int">
			<value>1</value>
		</constructor-arg>
		<constructor-arg index="1" type="java.lang.String">
			<value>Spring Bean生命周期</value>
		</constructor-arg>

		<!-- setter方法注入 -->
		<property name="id" value="2"/>
		<property name="name" value="zlw"/>
	</bean>

	<bean class="com.riemann.test.MyBeanPostProcessor" />

	<bean class="com.riemann.test.MyBeanFactoryPostProcessor" />
	
</beans>

⑥测试类

//测试类
public class BeanLifeCycleTest {
	public static void main(String[] args) {
		ApplicationContext applicationContext = new 
        ClassPathXmlApplicationContext("classpath:applicationContext.xml");
		UserBean user = (UserBean) applicationContext.getBean("userBean");
		((AbstractApplicationContext) applicationContext).close();
	}
}

⑦打印结果

0. 调用 BeanFactoryPostProcessor.postProcessBeanFactory()方法
1. 调用InstantiationAwareBeanPostProcessor.postProcessBeforeInstantiation()方法
2. 调用构造函数
3. 调用InstantiationAwareBeanPostProcessor.postProcessAfterInstantiation()方法UserBean{id=1, name='Spring Bean生命周期'}
4. 调用InstantiationAwareBeanPostProcessor.postProcessProperties()方法
5. 属性注入id
5. 属性注入name
6. 调用BeanNameAware. setBeanName()方法
UserBean{id=2, name= 'riemann '}
7. 调用 BeanNameAware. setBeanName()方法
8. 调用 BeanPostProcessor.postProcessBeforeInitialization()方法
9. 调用InitializingBean.afterPropertiesSet()方法
10.调用init-method 方法
11,调用BeanPostProcessor.postProcessAfterInitialization()方法
UserBean{id=2,name= 'riemann ' }
12.调用 DisposableBean.destroy()方法
13.调用destroy-method 方法

四、Spring Aop

Spring Aop是面向切片编程(方面),利用AOP可以对业务逻辑的各个部分进行隔离,从而使得业务逻辑各个部分之间的耦合度降低 提高程序的可重复性,同时提高了开发效率,AOP底层使用的是动态代理。

 ①Spring Aop的操作术语:

 ②切入点表达式:

//举例切入点表达式1,对com.atguigu.dao.BookDao类里面的add进行增强
//*表示所有权限修饰符,对返回值类型进行省略(void),对类路径BookDao下的add进行增强,(..)表示两个形参
execution(*com.atguigu.dao.BookDao.add(..))
    
//举例切入点表达式2,对com.atguigu.dao.BookDao类里面的所有方法进行增强
execution(*com.atguigu.dao.BookDao.*(..))
    
//举例切入点表达式3,对com.atguigu.dao包里面所有的类,类里面的所有方法进行增强
execution(*com.atguigu.dao.*.*(..))

③AspectJ注解对AOP的操作步骤一(创建类和增强类):

//User类
package com.atguigu.spring5.aopanno;

public class User{
    public void add(){ System.out.println("add......"); }
}

//增强类
package com.atguigu.spring5.aopanno;

public class UserProxy{
    //前置通知
    public void before(){ System.out.println("before....."); }
}

④进行通知配置

<bean>	
    <!--1.开启注解扫描-->
<context:component-scan base-package="com.atguigu.spring5.aopano"></context:component-scan>
	<!--4.开启AspectJ生成代理对象-->
    <aop:aspectj-autoproxy></aop:aspectj-autoproxy>
</beans>

⑤增强类上添加@AspectJ注解,并在类上加注解@Component使其能够扫描到

package com.atguigu.spring5.aopanno;

import org.springframework.stereotype.Component;

//2.被增强的类注解
@Component
public class User{
    public void add(){ System.out.println("add......"); }
}

package com.atguigu.spring5.aopanno;

import org.springframework.stereotype.Component;

//2.增强的类注解
@Component
//3.生成代理对象注解
@AspectJ
public class UserProxy{
    //前置通知
    public void before(){ System.out.println("before....."); }
}

⑥在代理类的通知方法上面添加通知类型注解,使用切入点表达式配置

package com.atguigu.spring5.aopanno;

import org.springframework.stereotype.Component;

//2.增强的类注解
@Component
//3.生成代理对象注解
@AspectJ
public class UserProxy{
    //前置通知
    //@Before表示前置通知,写切入点表达式
    @Before(value="execution(*com.atguigu.spring5.aopanno.User.add(..))")
    public void before(){ System.out.println("before....."); }
}

⑦各个通知举例说明

package com.atguigu.spring5.aopanno;

import org.springframework.stereotype.Component;

@Component
@AspectJ
public class UserProxy{
    //1.前置通知
    //@Before表示前置通知,写切入点表达式
    @Before(value="execution(*com.atguigu.spring5.aopanno.User.add(..))")
    public void before(){ System.out.println("before....."); }
    
    //2.最终通知,有没有异常都执行
    //@After表示后置通知
    @After(value="execution(*com.atguigu.spring5.aopanno.User.add(..))")
    public void after(){ System.out.println("after......"); }
    
    //3.环绕通知
    //@Around表示环绕通知
    @Around(value="execution(*com.atguigu.spring5.aopanno.User.add(..))")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{ 
        System.out.println("环绕之前......"); 
        //被增强的方法执行
        proceedingJoinPoint.proceed();
        System.out.println("环绕之后......");
    }
    
    //4.异常通知
    //@AfterThrowing表示异常通知
    @AfterThrowing(value="execution(*com.atguigu.spring5.aopanno.User.add(..))")
    public void afterThrowing(){ System.out.println("afterThrowing......"); }
    
    //5.后置通知(返回通知),有异常不执行
    //@AfterReturning表示异常通知
    @AfterReturning(value="execution(*com.atguigu.spring5.aopanno.User.add(..))")
    public void afterReturning(){ System.out.println("afterReturning......"); }
}

⑧相同切入点的提取

package com.atguigu.spring5.aopanno;

import org.springframework.stereotype.Component;

@Component
@AspectJ
public class UserProxy{
    
    //相同切入点抽取
    @Pointcut(value="execution(*com.atguigu.spring5.aopanno.User.add(..))")
    public void pointdemo(){  }
    
    @Before(value="pointdemo()")
    public void before(){ System.out.println("before....."); }
    
    @After(value="pointdemo()")
    public void after(){ System.out.println("after......"); }
    
    @Around(value="pointdemo()")
    public void around(ProceedingJoinPoint proceedingJoinPoint) throws Throwable{ 
        System.out.println("环绕之前......"); 
        //被增强的方法执行
        proceedingJoinPoint.proceed();
        System.out.println("环绕之后......");
    }
    
    @AfterThrowing(value="pointdemo()")
    public void afterThrowing(){ System.out.println("afterThrowing......"); }
    
    @AfterReturning(value="pointdemo()")
    public void afterReturning(){ System.out.println("afterReturning......"); }
}

⑨多个增强类对同一个方法进行增强,设置优先级

//在增强类上面添加一个注解@Order(数字类型的值),数字类型值越小优先级越高
package com.atguigu.spring5.aopanno;

import org.springframework.stereotype.Component;

@Component
@AspectJ
@Order(1)
public class UserProxy{
    //前置通知
    //@Before表示前置通知,写切入点表达式
    @Before(value="execution(*com.atguigu.spring5.aopanno.User.add(..))")
    public void before(){ System.out.println("user before....."); }
}

package com.atguigu.spring5.aopanno;

import org.springframework.stereotype.Component;

@Component
@AspectJ
@Order(3)
public class PersonProxy{
    //前置通知
    //@Before表示前置通知,写切入点表达式
    @Before(value="execution(*com.atguigu.spring5.aopanno.User.add(..))")
    public void before(){ System.out.println("person before....."); }
}

//@Order(1)>@Order(3)的优先级,先执行UserPorxy后执行PersonPorxy

⑩AOP的AspectJ配置文件或者完全注解开发

<bean>	
    <!--创建对象-->
	<bean id="user" class="com.atguigu.spring5.aopanno.User"></bean>
	<bean id="userProxy" class="com.atguigu.spring5.aopanno.UserProxy"></bean>

	<!--配置aop增强-->
	<aop:config >
        <!--切入点-->
    <aop:pointcut id="p"expression="execution(*com.atguigu.spring5.aopanno.User.add(..))">
          <!--配置切面-->
            <aop:aspect ref="userProxy">
              <!--增强作用在具体的方法上-->
                <aop:before method="before" pointcut-ref="p"/>
            </aop:aspect>
      </aop:pointcut>
	</aop:config>
</beans>
package com.atguigu.spring5.config;

import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

@Configuration
@ComponentScan(basePackage = {"com.atguigu"})
@EnableAspectJAutoProxy(proxyTargetClass = true)
public class ConfigAop{
    
}

最后

本文有参考很多大佬的文章,也有引用图片和内容,仅供于参考学习,如有错误还望指点。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值