spring注解详解

IOC

组件注册

1、@Configuration

作用:表示这个类是一个spring配置类,相当于spring的xml配置文件!

ps:其本身也是一个component组件

2、@Bean

作用:写在Configuration配置类中,其功能是声明一个Bean(写在一个方法上),相当于xml配置文件中的bean标签,默认使用方法名作为id,使用方法类型作为Bean的类型

@Bean("自定义的bean的id")
public ISqlInjector sqlInjector(){
    return new LogicSqlInjector();
}

3、@ComponentScan

作用:组件,向spring中注册

@ComponentScan(value = "com.atguigu",excludeFilters = {
        @ComponentScan.Filter(type = FilterType.ANNOTATION,classes = {Controller.class, Service.class})
})
//指定排除规则

FilterType过滤规则

  • FilterType.ANNOTATION:按照注释

  • FilterType.ASSIGNABLE_TYPE:按照给定的类型

  • FilterType.ASPECTJ:使用ASPECTJ表达式(不常用)

  • FilterType.REGEX:使用正则表达式

  • FilterType.CUSTOM:使用自定义规则(TypeFilter的实现类)

    • package com.atguigu.filter;
      
      import org.springframework.core.io.Resource;
      import org.springframework.core.type.AnnotationMetadata;
      import org.springframework.core.type.ClassMetadata;
      import org.springframework.core.type.classreading.MetadataReader;
      import org.springframework.core.type.classreading.MetadataReaderFactory;
      import org.springframework.core.type.filter.TypeFilter;
      
      import java.io.IOException;
      
      /**
       * @Author 回到原点
       * @Date 2021/4/20 14:35
       * @Version 1.0
       */
      public class MyTypeFilter implements TypeFilter {
          //metadataReader:读取到当前正在扫描的类的信息
          //metadataReaderFactory:可以获取到其他任何类的信息
          public boolean match(MetadataReader metadataReader, MetadataReaderFactory metadataReaderFactory) throws IOException {
              //获取当前正在扫描的类的注解信息
              AnnotationMetadata annotationMetadata = metadataReader.getAnnotationMetadata();
              //获取当前正在扫描的类的信息
              ClassMetadata classMetadata = metadataReader.getClassMetadata();
              //获取当前类的资源(类的路径等)
              Resource resource = metadataReader.getResource();
      
              String className = classMetadata.getClassName();
              System.out.println(className);
              if (className.contains("er")) {
                  return true;
              }
              return false;
          }
      }
      

4、@Scope

作用:指定作用域,prototype(多实例),singleton(单实例)

ps:在创建多个相同的对象时是新建,还是指向同一个

@Test
public void test02() {
    //加载配置类
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfig2.class);
    String[] beanDefinitionNames = applicationContext.getBeanDefinitionNames();
    for (String beanDefinitionName : beanDefinitionNames) {
        System.out.println(beanDefinitionName);
    }

    //spring默认单实例,多次获取的是同一个
    Person person = (Person) applicationContext.getBean("person");
    Person person2 = (Person) applicationContext.getBean("person");
    System.out.println(person == person2);

}

spring注解详解_第1张图片

package com.atguigu.config;

import com.atguigu.Person;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

/**
 * @Author 回到原点
 * @Date 2021/4/20 14:46
 * @Version 1.0
 */
@Configuration
public class MainConfig2 {


    /**
     * ConfigurableBeanFactory#SCOPE_SINGLETON SCOPE_SINGLETON}.
     *      * @since 4.2
     *      * @see ConfigurableBeanFactory#SCOPE_PROTOTYPE  prototype
     *      * @see ConfigurableBeanFactory#SCOPE_SINGLETON  singleton
     *      * @see org.springframework.web.context.WebApplicationContext#SCOPE_REQUEST
     *      * @see org.springframework.web.context.WebApplicationContext#SCOPE_SESSION
     * @return
     *
     * prototype:多实例   ioc容器并不会调用方法放在容器中,每次获取的时候才会调用方法创建对象
     * singleton:单实例(默认的) ioc容器启动,会调用方法创建对象放到ioc容器中,以后每次获取就直接从(map.get())容器中拿
     */
    @Scope("prototype")
    @Bean("person")
    public Person person() {
        return new Person("小明",20);
    }

}

5、@Lazy懒加载(只针对单实例)

懒加载:容器启动先不创建对象,第一次获取bean的时候再去创建对象,并初始化

    @Lazy
    @Bean("person")
    public Person person() {
        return new Person("小明",20);
    }

6、@Conditional

作用:按照一定条件进行判断,满足条件给容器中注册Bean(放在类上,满足条件类中所有的bean都会被装配)

需求:判断当前系统是window还是linux,如果是windows注入windows相应的bean

配置类

package com.atguigu.config;

import com.atguigu.Person;
import com.atguigu.condition.LinuxCondition;
import com.atguigu.condition.WindowsCondition;
import org.springframework.context.annotation.*;

/**
 * @Author 回到原点
 * @Date 2021/4/20 14:46
 * @Version 1.0
 */
@Configuration
public class MainConfig2 {


    @Lazy
    @Bean("person")
    public Person person() {
        return new Person("小明",20);
    }

    @Bean
    public Person person01() {
        return new Person("jack",15);
    }

    @Conditional({WindowsCondition.class})
    @Bean("windows")
    public Person person02() {
        return new Person("bill gus",60);
    }
    @Conditional({LinuxCondition.class})
    @Bean("linux")
    public Person person03() {
        return new Person("linus",48);
    }

}

配置windos规则

package com.atguigu.condition;

import org.springframework.beans.factory.config.ConfigurableListableBeanFactory;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
 * @Author 回到原点
 * @Date 2021/4/20 15:41
 * @Version 1.0
 */
public class WindowsCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {

        //获取到ioc使用的BeanFactory
        ConfigurableListableBeanFactory beanFactory = context.getBeanFactory();
        //获取类加载器
        ClassLoader classLoader = context.getClassLoader();
        //获取bean 定义的注册类
        BeanDefinitionRegistry registry = context.getRegistry();
        //获取当前环境信息
        Environment environment = context.getEnvironment();
        //获取当前操作系统
        String property = environment.getProperty("os.name");

        if (property.contains("Windows")) {
            return true;
        }

        return false;
    }
}

linux规则

package com.atguigu.condition;

import org.springframework.context.annotation.Condition;
import org.springframework.context.annotation.ConditionContext;
import org.springframework.core.env.Environment;
import org.springframework.core.type.AnnotatedTypeMetadata;

/**
 * @Author 回到原点
 * @Date 2021/4/20 15:41
 * @Version 1.0
 */
public class LinuxCondition implements Condition {
    public boolean matches(ConditionContext context, AnnotatedTypeMetadata metadata) {
        Environment environment = context.getEnvironment();
        //获取当前操作系统
        String property = environment.getProperty("os.name");

        if (property.contains("linux")) {
            return true;
        }
        return false;
    }
}

测试

@Test
public void test03() {
    //根据类型获取bean
    String[] beanNamesForType = applicationContext.getBeanNamesForType(Person.class);
    for (String s : beanNamesForType) {
        System.out.println(s);
    }

}

7、@Import

作用:通过快速导入的方式实现把实例加入spring的IOC容器中(只能作用在类上)

加入IOC容器的方式有很多种,@Import注解就相对很牛皮了,**@Import注解可以用于导入第三方包** ,当然@Bean注解也可以,但是@Import注解快速导入的方式更加便捷

三种用法

  • 直接填class数组方式
  • ImportSelector方式【重点】
  • ImportBeanDefinitionRegistrar方式

直接填class数组方式:

@Import({类名.class, 类名.class})
public class MainConfig2 {
}

ImportSelector接口

返回需要导入的组件的全类名数组,将实现了这个接口的类写到Import注解上,这样返回的全类名就都会被装配到ioc容器中

spring注解详解_第2张图片

spring注解详解_第3张图片

ImportBeanDefinitionRegistrar

同样是一个接口,类似于第二种ImportSelector用法,相似度80%,只不过这种用法比较自定义化注册,可以实现一些简单的逻辑判断

8、FactoryBean(不是注解是接口)

FactoryBean是一个工厂Bean,可以生成某一个类型Bean实例,它最大的一个作用是:可以让我们自定义Bean的创建过程

先来看一下FactoryBean中有什么东西

public interface FactoryBean<T> {

    //返回的对象实例
    T getObject() throws Exception;
    //Bean的类型
    Class<?> getObjectType();
    //true是单例,false是非单例  在Spring5.0中此方法利用了JDK1.8的新特性变成了default方法,返回true
    boolean isSingleton();
}

具体实现

public class MyFactoryBean implements FactoryBean {

    public Object getObject() throws Exception {
        System.out.println("getobject.....");
        return new Color();
    }

    public Class<?> getObjectType() {
        return Color.class;
    }

    public boolean isSingleton() {
        return true;
    }
}

在配置类中注册Bean

@Bean
public MyFactoryBean factoryBean() {
    return new MyFactoryBean();
}

测试

@Test
public void testImport() {
    Object bean = applicationContext.getBean("factoryBean");
    System.out.println(bean+"的类型");
    soutBeanNames(applicationContext);
}

运行结果

spring注解详解_第4张图片

spring注解详解_第5张图片

9、@Nullable

  • @NonNull可以标注在方法、字段、参数之上,表示对应的值不可以为空
  • @Nullable注解可以标注在方法、字段、参数之上,表示对应的值可以为空(如果标注在接口的方法上,那么实现接口后不会强制重写方法)

以上两个注解在程序运行的过程中不会起任何作用,只会在IDE、编译器、FindBugs检查、生成文档的时候有做提示;我使用的IDE是STS,不会做自动的检查,只有安装了FindBugs插件并运行后会做对应的提示,

生命周期

bean的生命周期:

  • bean创建-----初始化------销毁的过程
  • 当前是容器在管理bean的生命周期
  • 我们可以自定义初始化和销毁的方法,容器在bean进行到当前生命周期的时候来调用我们自定义的初始化和销毁方法

四种方法

  1. 在bean上指定初始化和销毁方法 initMethod destroyMethod

  2. 通过让bean实现 InitializingBean(定义初始化逻辑)
    DisposableBean(定义销毁逻辑)

  3. 可以使用JSR250:@PostConstruct,在bean创建完成并且属性赋值完成,来执行初始化方法
    @PreDestroy,在容器销毁bean之前通知我们进行清理工作

  4. BeanPostProcessor:bean的后置处理器;在bean初始化前后进行一些处理工作;

    • spring底层对于BeanPostProcessor的使用;

      bean的赋值,注入其他组件,@Autowired,生命周期注解功能,@Async,xxx 都是使用的BeanPostProcessor

指定初始化和销毁方法 @Bean(initMethod = “方法名”,destroyMethod = “方法名”)

package com.atguigu.config;

import com.atguigu.beans.Car;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Scope;

/**
 * @Author 回到原点
 * @Date 2021/4/21 15:17
 * @Version 1.0
 * 
 *
 * 构造(对象创建)
 *      单实例,在容器启动的时候创建对象
 *      多实例,在每次获取的时候创建对象
 * 初始化:
 *      对象创建完成,并赋值好,调用初始化方法....
 * 销毁:
 *      单实例:容器关闭的时候
 *      多实例:容器不会管理这个bean,容器不会调用销毁方法;手动调用
 *
 *  1)、在bean上指定初始化和销毁方法 initMethod destroyMethod
 *  2)、通过让bean实现 InitializingBean(定义初始化逻辑)
 					DisposableBean(定义销毁逻辑)
 	3)、可以使用JSR250:@PostConstruct,在bean创建完成并且属性赋值完成,来执行初始化方法
    				@PreDestroy,在容器销毁bean之前通知我们进行清理工作
    4)、BeanPostProcessor:bean的后置处理器
 */
@Configuration
public class MainConfigOfLifeCycle {


    @Bean(initMethod = "init",destroyMethod = "destory")
    public Car car() {
        return new Car();
    }

}

car.class

public class Car {

    public Car() {
        System.out.println("car constructor......");
    }

    public void init() {
        System.out.println("car init......");
    }

    public void destory() {
        System.out.println("car destory......");
    }

}

spring注解详解_第6张图片

通过让bean实现接口

public class Car implements InitializingBean, DisposableBean {

    public Car() {
        System.out.println("car constructor......");
    }


    public void destroy() throws Exception {
        System.out.println("car destroy");
    }

    public void afterPropertiesSet() throws Exception {
        System.out.println("car init...");
    }
}

使用JSR250

public class Car {

    public Car() {
        System.out.println("car constructor......");
    }

    @PostConstruct
    public void init() {
        System.out.println("car init......");
    }
    @PreDestroy
    public void destory() {
        System.out.println("car destory......");
    }

}

BeanPostProcessor

postProcessBeforeInitialization:在初始化之前工作

postProcessAfterInitialization:在初始化之后工作

package com.atguigu.beans;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;
import org.springframework.stereotype.Component;

/**
 * @Author 回到原点
 * @Date 2021/4/21 16:01
 * @Version 1.0
 * 后置处理器
 */
@Component
public class MyBeanPostProcessor implements BeanPostProcessor {

    //初始化前
    public Object postProcessBeforeInitialization(Object bean, String beanName) throws BeansException {
        //谁被创建这个bean获取的就是谁
        System.out.println("before..."+beanName+"=>"+bean);
        return bean;
    }

    //初始化后
    public Object postProcessAfterInitialization(Object bean, String beanName) throws BeansException {
        System.out.println("before..."+beanName+"=>"+bean);
        return bean;
    }
}

spring注解详解_第7张图片

ps:每一个对象在初始化之前,都会调用方法(aop概念)

普通组件获取ioc容器的方法(实现ApplicationContextAware接口)

@Component
public class Cat implements ApplicationContextAware {
    private ApplicationContext applicationContext;
    
    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        this.applicationContext = applicationContext;
    }
}

属性赋值

1、@Value

作用:写在实体类的属性上方,可以为属性赋值

1.可以写基本数据类型
2.可以写spEL;#{}
3.可以写${},取出配置文件中的值

person实体类

package com.atguigu;

import org.springframework.beans.factory.annotation.Value;

/**
 * @Author 回到原点
 * @Date 2021/4/20 14:47
 * @Version 1.0
 */
public class Person {

    /**
     * 使用@value赋值
     * 1.可以写基本数据类型
     * 2.可以写spEL;#{}
     * 3.可以写${},取出配置文件中的值
     */
    @Value("张三")
    private String name;
    @Value("#{25-10}")
    private Integer age;

    public Person() {
    }

    public Person(String name, Integer age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Integer getAge() {
        return age;
    }

    public void setAge(Integer age) {
        this.age = age;
    }
}

结果

spring注解详解_第8张图片

2、@PropertySource

作用:读取外部配置文件,写在Configuration配置类上、

和@Value配合使用:${},取出配置文件中的值

配置文件

spring注解详解_第9张图片

//使用PropertySource获取配置文件中的key-value保存到环境变量中
@PropertySource(value = {"classpath:/person.properties"})
@Configuration
public class MainConfigOfPropertyValues {


    @Bean
    public Person person() {
        return new Person();
    }

}

spring注解详解_第10张图片

自动装配

1、@Autowired

作用:自动装配(注入)bean;先按类型查找,如果有多个相同的类型,根据id名称查找(默认名称是方法名首字母小写);注意,是从ioc容器中获取并自动注入到当前类中,而@Bean是将类注册到IOC容器中,两个的功能并不相同

1.1 @Autowired(构造器,参数,方法,属性;都是从容器中获取参数的组件值)

@Autowired是一种注解,可以对成员变量、方法和构造函数进行标注,来完成自动装配的工作,@Autowired标注可以放在成员变量上,也可以放在成员变量的set方法上,也可以放在任意方法上表示,自动执行当前方法,如果方法有参数,会在IOC容器中自动寻找同类型参数为其传值。

这里必须明确:@Autowired是根据类型进行自动装配的,如果需要按名称进行装配,则需要配合@Qualifier使用;

1.1.1 构造器注入

@RestController
public class UserController {
private UserService userService;

@Autowired
public UserController(UserService userService) {
this.userService = userService;
    }
}

1.1.2 setter方法注入

@RestController
public class UserController {
private UserService userService;

@Autowired
public void setUserService(UserService userService) {
this.userService = userService;
    }
}

1.1.3 field反射注入

@RestController
public class UserController {
@Autowired
private UserService userService;
}

2、@Qualifier

上面已经说到@Autowired按类型装配Spring Bean。如果容器中有多个相同类型的bean,则框架将抛出NoUniqueBeanDefinitionException, 以提示有多个满足条件的bean进行自动装配。程序无法正确做出判断使用哪一个,通过将@Qualifier注解与我们想要使用的特定Spring bean的名称一起进行装配,Spring框架就能从多个相同类型并满足装配要求的bean中找到我们想要的,

@Component("studentInfo")
public class StudentInfo implements UserInfo {
public String userName() {
return "student";
    }
}

@Component("teacherInfo")
public class TeacherInfo implements UserInfo {
public String userName {
return "teacher";
    }
}

@Component
public class UserService {
@Autowired
@Qualifier("studentInfo")
private UserInfo userInfo;

//todo 
}

3、@Primary(首选的)

作用:让spring进行自动装配的时候,默认使用首选的bean,不能和Qualifier同时使用,(用于有多个相同的类型不同的名称的bean)

@Configuration
public class MainConfigOfPropertyValues {


    @Primary
    @Bean
    public Person person() {
        return new Person();
    }

}

4、@Resource

spring还支持使用@Resource(JSR250)和@Inject(JSR330)[java规范的注解]

作用:类似Autowired也可以完成自动装配,默认按照组件名称进行装配没有能支持@Primary功能没有支持@Autowired(reqiured=false);

@Resource(name = "bookDao")

@Inject:需要导入javax.inject的包,和Autowired的功能一样

区别:Autowired是Spring定义的功能相对来说要多,Resource和Inject是java定义的规范脱离spring框架也可以使用

5、Aware接口

自定义组件想要实现Spring容器底层的一些组件(ApplicationContext,BeanFactory,xxx)时,自定义组件只需要实现xxxAware接口,在创建对象的时候,会调用接口规定的方法注入相关组件;

public class Red implements ApplicationContextAware, BeanNameAware, EmbeddedValueResolverAware {

    public void setApplicationContext(ApplicationContext applicationContext) throws BeansException {
        System.out.println("传入的Ioc"+applicationContext);
    }

    public void setBeanName(String s) {
        System.out.println("当前bean的名字"+s);
    }

    public void setEmbeddedValueResolver(StringValueResolver resolver) {
        //解析字符串
        resolver.resolveStringValue("你好${os.name} 我是#{80-50}");
    }
}

xxxAware:对应的功能使用xxxProcessor实现

6、@Profile

作用:Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;(在springboot中被配置文件所替代)

开发环境develop、测试环境test、生产环境master
数据源:(/dev) (/test) (/master)

@Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件

  1. 加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境
  2. 写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效
package com.spring.config;

import java.beans.PropertyVetoException;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.EmbeddedValueResolverAware;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Profile;
import org.springframework.context.annotation.PropertySource;
import org.springframework.util.StringValueResolver;

import com.mchange.v2.c3p0.ComboPooledDataSource;

/**

 * Profile:

 * Spring为我们提供的可以根据当前环境,动态的激活和切换一系列组件的功能;

 * 

 * 开发环境develop、测试环境test、生产环境master

 * 数据源:(/dev) (/test) (/master)
   *

 * @Profile:指定组件在哪个环境的情况下才能被注册到容器中,不指定,任何环境下都能注册这个组件

 * 

 * 1) 加了环境标识的bean,只有这个环境被激活的时候才能注册到容器中。默认是default环境

 * 2) 写在配置类上,只有是指定的环境的时候,整个配置类里面的所有配置才能开始生效

 * */
   @PropertySource("classpath:/dbconfig.properties")
   @Configuration
   public class MainConfigOfProfile implements EmbeddedValueResolverAware{

   @Value("${db.user}")
   private String user;

   private String driverClass;

   @Profile("default")
   @Bean("test")
   public DataSource testDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
   	ComboPooledDataSource dataSource = new ComboPooledDataSource();
   	dataSource.setUser(user);
   	dataSource.setPassword(password);
   	dataSource.setDriverClass(driverClass);
   	return dataSource;
   }

   @Profile("dev")
   @Bean("dev")
   public DataSource devDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
   	ComboPooledDataSource dataSource = new ComboPooledDataSource();
   	dataSource.setUser(user);
   	dataSource.setPassword(password);
   	dataSource.setDriverClass(driverClass);
   	return dataSource;
   }

   @Profile("master")
   @Bean("master")
   public DataSource masterDataSource(@Value("${db.password}")String password) throws PropertyVetoException {
   	ComboPooledDataSource dataSource = new ComboPooledDataSource();
   	dataSource.setUser(user);
   	dataSource.setPassword(password);
   	dataSource.setDriverClass(driverClass);
   	return dataSource;
   }

   public void setEmbeddedValueResolver(StringValueResolver resolver) {
   	String driverClass = resolver.resolveStringValue("${db.driverClass}");
   	this.driverClass = driverClass;
   }

}
package com.spring.test;

import java.util.Arrays;

import javax.sql.DataSource;

import org.junit.Test;
import org.springframework.context.annotation.AnnotationConfigApplicationContext;

import com.spring.config.MainConfigOfProfile;


public class IOCTestProfile {
	//1. 使用命令行动态参数:在虚拟机参数位置加载 -Dspring.profiles.active=test
	//2. 使用代码的方式激活某种环境;
	@Test
	public void test01() {
		AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);
		//1. 创建一个applicationContext
		//2. 设置需要激活的环境
		applicationContext.getEnvironment().setActiveProfiles("dev","master");
		//3. 注册主配置类
		applicationContext.register(MainConfigOfProfile.class);
		//4. 启动刷新容器
		applicationContext.refresh();
	String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class);
	System.out.println(Arrays.toString(beanNamesForType));
	
	applicationContext.close();
}
@Test
public void test02() {
	AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(MainConfigOfProfile.class);
	
	String[] beanNamesForType = applicationContext.getBeanNamesForType(DataSource.class);
	System.out.println(Arrays.toString(beanNamesForType));
	
	applicationContext.close();
}
}

AOP

AOP功能测试

导入包


    org.springframework
    spring-aspects
    5.3.2

下方一系列注解使用方法详见最后的代码部分

@EnableAspectJAutoProxy

作用:开启切面自动代理写在Configuration配置类上;详见最后的代码部分

@Aspect

作用:告诉spring当前类是切面类;详见最后的代码部分

@Pointcut

作用:抽取要切入的目标函数;详见最后的代码部分

  /**
     * 抽取切入函数
     * *代表所有方法,..代表所有参数
     */
@Pointcut("execution(public int com.atguigu.beans.MathMaratic.*(..))")

@Before(要切入的目标函数)

作用:在目标方法(除法div)运行之前运行;详见最后的代码部分

@After

作用:在目标方法(除法div)运行之后运行;详见最后的代码部分

@AfterReturning

作用:在目标方法(除法div)正常返回之后运行;详见最后的代码部分

@AfterThrowing

作用:在目标方法(除法div)出现异常以后运行;详见最后的代码部分

=======================================================================================================================================

config配置类

package com.atguigu.config;

import com.atguigu.Aspect.LogAspects;
import com.atguigu.beans.MathMaratic;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.EnableAspectJAutoProxy;

/**
 * @Author 回到原点
 * @Date 2021/4/23 9:41
 * @Version 1.0
 */
@Configuration
@EnableAspectJAutoProxy//开启切面自动代理
public class MainConfigOfAspect {


    @Bean(initMethod = "init",destroyMethod = "destory")
    public MathMaratic mathMaratic() {
        return new MathMaratic();
    }
    @Bean
    public LogAspects logAspects() {
        return new LogAspects();
    }

}

业务逻辑类

package com.atguigu.beans;

/**
 * @Author 回到原点
 * @Date 2021/4/23 9:30
 * @Version 1.0
 */
public class MathMaratic {

    public int div(int i, int j) {
        System.out.println("div excutive");
        return i/j;
    }

    /*这里尝试了一下@Bean注解的init和destroy,init的优先级要高于切入
    public void init() {
        System.out.println("init");
    }

    public void destory() {
        System.out.println("destory");
    }*/

}

切面配置类

package com.atguigu.Aspect;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.*;

import java.util.Arrays;

/**
 * @Author 回到原点
 * @Date 2021/4/23 9:31
 * @Version 1.0
 */
//告诉spring这是切面类
@Aspect
public class LogAspects {

    /**
     * 抽取切入函数
     * *代表所有方法,..代表所有参数
     */
    @Pointcut("execution(public int com.atguigu.beans.MathMaratic.*(..))")
    public void pointCut(){};

    /**
     * Before(要切入的目标函数)
     * 可以直接使用上方抽取的函数的方法名
     */
    @Before("pointCut()")
    public void logBefore(JoinPoint joinPoint) {
        Object[] args = joinPoint.getArgs();
        System.out.println("除法执行前...方法名{"+joinPoint.getSignature().getName()+"}...参数"+ Arrays.asList(args));
    }
    @After("pointCut()")
    public void logAfter() {
        System.out.println("除法正常执行后...");
    }

    @AfterReturning(value = "pointCut()",returning = "result")
    public void logAfterReturn(Object result) {
        System.out.println("除法正常返回...."+result);
    }
    @AfterThrowing(value = "pointCut()",throwing = "except")
    public void logException(JoinPoint joinPoint,Exception except) {
        //这里joinpoint一定要放在第一个
        System.out.println(joinPoint.getSignature().getName()+"除法异常...."+except);
    }

}

JoinPoint:可以获取到目标函数的名字,参数等

JoinPoint参数一定要出现在参数的第一位

AOP原理详解

1、@EnableAspectJAutoProxy

@Import(AspectJAutoProxyRegistrar.class)

声明式事务

@EnableTransactionManagement

作用:开启基于注解的事务管理功能,写在config类上

@Transactional

作用:在方法上标注@Transactional注解,表示当前方法是一个事务方法;如果出现任何异常,回滚状态(需要和EnableTransactionManagement配合使用)

要想成功使用事务必须要注入PlatformTransactionManager

@Bean
public PlatformTransactionManager platform() {
    //事务必须要管理数据源
    return new DataSourceTransactionManager(dataSource())
}

你可能感兴趣的:(spring,java,aop,bean,ioc)