Spring系列--注解

98 阅读3分钟

Spring系列--注解

第一章 注解基础概念

1、什么是注解编程

指的是在类或者方法上加入特定的注解(@xxxx),完成特定功能的开发
	@Component
	public class XXX{}

2、为什么要讲注解编程

1. 注解开发方便
	代码简洁  开发速度大大提高
2. Spring 开发潮流
	Spring2.x引入注解   Spring3.x完善注解   SpringBoot普及   推广注解编程

3、注解的作用

  • 替换xml这种配置形式,简化配置

  • 替换接口,实现调用双方的契约性

    通过注解的方式,在功能调用者和功能提供者之间达成约定,进而进行功能的调用,因为注解应用更为灵活方便,所以在现在开发中,更推荐通过注解的形式完成
    

4、Spring注解的发展历程

1. Spring2.x 开始支持注解编程 @Component @Service @Scope....
	目的:提供这些注解只是为了在某些情况下简化xml的配置,作为xml开发的有益补充
2. Spring3.x @Configuration @Bean...
	目的:彻底替换xml,基于纯注解编程
3. Spring4.x SpringBoot
	提倡使用注解常见开发

5、Spring注解开发的一个问题

Spring基于注解进行配置后,还能否解耦合呢
-- 在Spring框架应用注解时,如果对注解配置的内容不满意,可以通过Spring配置文件进行覆盖的

第二章 Spring的基础注解(Spring2.x)

1、对象创建相关注解

  • 搭建开发环境

    <context:component-scan base-package="com.bai"/>
    
    作用:让Spring框架在设置包及其子包中扫描对应的注解,使其生效
    
  • 对象创建相关注解

    • @Component

      作用:替换原有spring配置文件中的<bean>标签
      注解:id属性 component注解,提供了默认的设置方式,受单词首字母小写
      	 class属性通过反射获得class内容
      
    • @Component细节

      • 如何显示指定工厂创建对象的id值

        @Conponent("")
        
      • Spring配置文件覆盖注解配置内容

        applicationContext.xml
        <bean id="u" class="com.bai.bean.User"/>
        id值和class值  要和注解中的设置保持一致
        
    • @Component的衍生注解

      @Repository
      @Service
      @Controller
      注意:本质上这些衍生注解就是@Component
      目的:准确的表达一个类型的作用
      
      注意:Spring整合Mybatis开发过程中,不适用@Repostitory @Conponent
      
    • @Scope注解

      作用:控制简单对象创建次数
      注意:不添加@Scope Spring提供默认值 singleten
      
    • @Lazy注解

      作用:延迟创建单实例对象
      注意:一旦使用了@Lazy注解后,Spring会在使用这个对象时候,进行这个对象的创建
      
  • 生命周期方法相关注解

    1. 初始化相关方法@PostConstruct
    	InitializingBean
    	<bean init-method=""/>
    2. 销毁方法@PreDestroy
    	DisposableBean
    	<bean destory-method=""/>
    
    注意:1.上述的两个注解并不是Spring提供的,JSP(javaEE规范)520
    	 2.再一次验证,通过注解实现了接口的契约性
    

2、注入相关注解

  • 用户自定义类型@Autowired

    @Autowired细节
    1. Autowired注解基于类型进行注入【推荐】
    	基于类型的注入:注入对象的类型,必须与目标成员变量类型相同或者是其子类(实现类)
    2. Autowired Qualifier 基于名字进行注入【了解】
    	基于名字注入:注入对象的id值,必须与Qualifier注解中设置的名字相同
    3. Autowired注解放置位置
       a) 放置在对应成员变量的set方法上
       b) 直接把这个注解放置在成员变量之上,Spring通过反射直接对成员变量进行注入(赋值)【推荐】
    4. JavaEE规范中类似功能的注解
    	JSR250 @Resource(name="userDAOImpl")基于名字进行注入
    		   @Autowired()
    		   @Qualifier("userDAOImpl")
    		   
    	注意:如果在应用Resource注解时,名字没有配对成功,那么他会继续按照类型进行注入
    	JSR330 @Inject 作用 @Autowired完全一致  基于类型进行注入 ---> EJB3.0
    	<dependency>
    		<groupId>java.inject</groupId>
    		<artifactId>javax.inject</artifactId>
    		<version>1</version>
    	</dependency>
    
  • JDK类型

    @Value注解完成
    1. 设置xxxx.properties
      id = 10
        name = suns
    2. Spring的工厂读取这个配置文件
    	<context:property-placeholder location=""/>
    3. 代码
    	属性@value("${key}")
    
    • @PropertySource

      1. 作用:用于替换Spring配置文件中的<context:property-placeholder location=""/>
      
    • @Value注解使用细节

      • @Value注解不能应用在静态成员变量上
      • @Value注解+properties方式,不能应用在集合成员变量上

3、注解扫描详解

<context:component-scan base-package="com.bai"/>
当前包及其子包
  • 排除方式

    <context:component-scan base-package="coom.bai">
    	<context:exclude-filter type="" expression=""/>
    	type:assignable:排除特定的类型  不进行扫描
    		 annotation:排除特定的注解  不进行扫描
    		 aspectj:切入点表达式
    		 		  包切入点:.com.bai.bean..*
    		 		  类切入蒂娜:*..User
    		 regex:正则表达式
    		 custom:自定义排除策略   框架底层开发
    </context:component-scan>
    
    排除策略是可以叠加使用的
    
  • 包含方式

    <context:component-scan base-package="com.bai" user-default-filters="false">
    	<context:include-filter type="" expression=""/>
    </context:component-scan>
    
    1.use-default-filters="false"
      作用:让Spring默认的注解扫描方式失效
    2.<context:include-filter type="" expression=""/>
      作用:扫描指定的注解
      type:assignable:扫描特定的类型 
    		 annotation:扫描特定的注解  
    		 aspectj:切入点表达式
    		 		  包切入点:.com.bai.bean..*
    		 		  类切入蒂娜:*..User
    		 regex:正则表达式
    		 custom:自定义排除策略   框架底层开发
    		 
    包含的方式支持叠加
    

4、对于注解开发的思考

  • 配置互通

    注解和配置文件可以互通
    
  • 什么情况下使用注解,什么情况下使用配置文件

5、SSM整合开发(半注解)

第三章 Spring的高级注解(Spring3.x版本以上)

1、配置Bean

Spring在3.x提供的新的注解,用于替换XML配置文件

@Configuration
public class AppConfig{

}
  • 配置Bean在应用的过程中,替换了XML具体的什么内容?

    替换了ApplicationContext.xml的全部工作
    
  • AnnotationConfigApplicationCotext

    1. 创建工厂代码
    	ApplicationContext ctx = new AnnotationConfigApplicationCotext();
    2. 指定配置文件
    	1.指定配置Bean的class
    	ApplicationContext ctx = new AnnotationConfigApplicationCotext(AppConfig.class);
    	2.指定配置Bean的所在路径
    	ApplicationContext ctx = new AnnotationConfigApplicationCotext("com.bai");
    
1、集成logback
  • 引入相关jar包

    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.3.0-alpha5</version>
        <scope>test</scope>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>2.0.0-alpha1</version>
    </dependency>
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>2.0.0-alpha1</version>
    </dependency>
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.3.0-alpha5</version>
    </dependency>
    <dependency>
        <groupId>org.logback-extensions</groupId>
        <artifactId>logback-ext-spring</artifactId>
        <version>0.1.5</version>
    </dependency>
    
  • 引入logback的配置文件(logback.xml)

    <?xml version="1.0" encoding="UTF-8"/>
    <configuration>
    	<!--控制台输出-->
    	<appender name="STDOUT" class="ch.qos.logback.core.ConsoleAppenfer">
      		<encoder>
    			<!--格式化输出:%d表示日期,%thread表示线程名,%-5level:级别从左显示5个字符宽度%msg:日志消息,%n是换行符-->
       			<pattern>%d{yyyy-MM-dd HH:mm:ss.SSS} [%thread] %-5level %logger{50} - %msg%n</pattern>
    		</encoder>
     	</appender>
    
     	<root level="DEBUG">
    		<appender-ref ref="STDOUT"/>
    	</root>
    </configuration>
    
  • @Configuration注解的本质

    本质:也是@Component注解的衍生注解
    
    可以应用<context:component-scan>进行扫描
    

2、@Bean注解

@Bean注解在配置bean中进行使用,等同于XML配置文件中的<bean>标签
1、@Bean注解的基本使用
  • 对象的创建

    1. 简单对象
    	直接能够通过new方式创建的对象
    	User UserService UserDAO
    2. 复杂对象
    	不能通过new的方式直接创建的对象
    	Connection  SqlSessionFactory
    
    @Configuration
    public class AppConfig{
        /**
        *简单对象
        */
        @Bean
        public User user(){
            return new User();
        }
        
        /**
        *创建复杂对象
        */
        @Bean
        public Connection conn(){
            Connection conn = null;
            try{
                Class.forName("com.mysql.jdbc.Driver");
                conn = DriverManager.getConnection("jdbc:mysql://localhost:3306/sun?userSSL=false","root","123455");
            }catch (ClassNotFoundException e){
                e.printStackTrace();
            }catch(SQLException e){
                e.printStackTrace();
            }
            return conn;
        }
    }
    
    • @Bean注解创建复杂对象的注意事项

      public Connection conn{
          Connection conn = null;
          try{
              ConnectionFactoryBean factoryBean = new ConnectionFactoryBean();
              conn = factoryBean.getObject();
          } catch (Exception e){
              e.printStackTrace();
          }
          return conn;
      }
      
  • 自定义id值

    @Bean("id")
    
  • 控制对象创建次数

    @Bean
    @Scope("singleton|prototype") 默认值  singleton
    
2、@Bean注解的注入
  • 用户自定义类型

    @Bean
    public UserDAO userDAO(){
        return new UserDAOImpl();
    }
    
    @Bean
    public UserService userService(UserDAO userDAO){
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDAO(userDAO);
        return userService;
    }
    
    // 简化写法
    @Bean
    public UserService userService(){
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDAO(userDAO());
        return userService;
    }
    
  • JDK类型的注入

    @Bean
    public Customer customer(){
        Customer customer = new Customer();
        customer.setId(1);
        customer.setName("xxx");
        
        return customer;
    }
    
    • JDK类型注入的细节分析

      如果直接在代码中进行set方法的调用,会存在耦合的问题
         
      @Configuration
      @PropertySource("classpath:/init.properties")
      public class AppConfig{
          @Value("${id}")
          private Integer id;
          @Value("${name}")
          private String name;
          
          @Bean
          public Customer cutomer(){
              Customer customer = new Customer();
              customer.setId(id);
              customer.setName(name);
              
              return customer;
          }
      }
      
3、@ComponentScan注解
@ComponenScan猪妹在配置bean中进行使用,等同于XML配置文件中的<context:component-scan>标签

目的:进行相关注解的扫描 (@Compomemt @Value...@Autowired)
1、基本使用
@Configuration
@ComponentScan(basePackages="com.bai.scan")
public class AppConfig{
    
}

等同于<context:component-scan base-package=""/>
2、排除、包含的使用
  • 排除

    <context:component-scan base-package="com.bai">
       	<context:exclude-filter type="assignable" expression="com.bai.bean.user"></context:exclude-filter>
    </context:component-scan>
    
    @ComponentScan(basePackage = "com.bai.scan",
    				excludeFilters = {@ComponentScan.Filter(type=FilterType.ANNOTATION,value={Service.class}),
     @ComponentScan.Filter(Type=FilterType.ASPECTJ,pattern="*.user1")})
    
    type = FilterType.ANNOTATION 		value
    				 .ASSIGNABLE_TYPE	value
    				 .ASPECTJ			pattern
    				 .REGEX				pattern
    				 .CUSTOM			value
    
  • 包含

    <context:component-scan base-package="com.bai" use-default-filters="false">
       	<context:include-filter type="assignable" expression="com.bai.bean.user"></context:include-filter>
    </context:component-scan>
    
    @ComponentScan(basePackage = "com.bai.scan", useDefaultFilters= false,
    				includeFilters = {@ComponentScan.Filter(type=FilterType.ANNOTATION,value={Service.class}),
     @ComponentScan.Filter(Type=FilterType.ASPECTJ,pattern="*.user1")})
     
     type = FilterType.ANNOTATION 		value
    				 .ASSIGNABLE_TYPE	value
    				 .ASPECTJ			pattern
    				 .REGEX				pattern
    				 .CUSTOM			value
    
4、Spring工厂创建对象的多种配置方式
1、多种配置方式的应用场景
@Component    			平常开发
@Bean					框架和别人的代码
<bean></bean>			整合旧的系统
2、配置优先级
@Component及其衍生注解 < @Bean < 配置文件bean标签
优先级高的配置   覆盖优先级低配置
  • 解决基于注解进行配置的耦合问题

    @Configurationo
    @ImportResource("applicationContext.xml")
    public class AppConfig{
    
    	@Bean
    	public UserDAO userDAO(){
    		return new UserDAOImpl();
    	}
    }
    
    applicationContext.xml
    <bean id="userDAO" class="com.bai.injection.userDAOImplNew"/>
    
5、整合多个配置信息
  • 为什么会有多个配置信息

    拆分多个配置bean的开发,是一种模块化开发的形式,也体现了面向对象各司其职的设计思想
    
  • 多配置信息的整合方式

    • 多个配置Bean的整合
    • 配置Bean与@Component相关注解的整合
    • 配置Bean与SpringXML配置文件的整合
  • 整合多种配置徐哟啊关注哪些要点

    • 如何使多配置的信息汇总成一个整体
    • 如何实现跨配置的注入
1、多配置Bean的整合
  • 多配置的信息汇总

    • base-package进行多个配置Bean的整合

    • @Import

      1. 可以创建对象
      2. 多配置bean的整合
      
    • 在工厂创建时,指定多个配置Bean的Class对象【了解】

      ApplicationContext ctx = new AnnotationConfigApplicationConext(AppConfig1.class,Appconfig2.class);
      
  • 跨配置进行注入

    在应用配置Bean的过程中,不管使用哪种方式进行配置信息的汇总,其操作方式都是通过成员变量加入@Autowired注解完成
        
    @Configuration
    @Import(AppConfig2.class)
    public class AppConfig1{
        @Autowired
        private UserDAO userDAO;
        
        @Bean
        public UserService userService(){
            UserServiceImpl userService = new UserServiceImpl();
            userService.setUserDAO(userDAO);
            return userService;
        }
    }
    
    @Configuration
    public class AppConfig2{
        
        @Bean
        public UserDAO userDAO(){
            return new UserDAOImpl();
        }
    }
    

2、配置Beanyu@Component相关注解的整合

@Component(@Repository)
public class UserDAOImpl implements UserDAO{

}

@Configuration
@ComponentScan("")
public class AppConfig2{

	@Autowired
	private UserDAO userDAO;
	
	@Bean
	public UserService userService(){
		UserServiceImpl userService = new UserServiceImpl();
		userService.setUserDAO(userDAO);
		return userService;
	}
}

ApplicationContext ctx = new AnnotationConfigApplicationConext(AppConfig3.class);
3、配置Bean与配置文件整合
1. 遗留系统的整合  2. 配置覆盖

public class UserDAOImpl implements UserDAO{

}
<bean id="userDAO" class="com.bai.injection.UserDAOImpl"/>

@Configuration
@ImportResource("applicationContext.xml")
public class Appconfig4{

	@Autowired
	private UserDAO userDAO;
	
	@Bean
	public UserService userService(){
		UserServiceImpl userService = new UserServiceImpl();
		userService.setUserDAO(userDAO);
		return userService;
	}
}
ApplicationContext ctx = new AnnotationConfigApplicationConext(AppConfig4.class);
6、配置Bean底层实现原理
Spring在配置Bean中加入了@Configuration注解后,底层就会通过Cglib的代理方式,来进行对象相关的配置、处理
7、四维开发一体的开发思想
  1. 什么是四维一体

    Spring开发一个功能的4中形式,虽然开发方式不同,但是最终效果都是一样的
    1. 基于schema
    2. 基于特定功能注解
    3. 基于原始<bean>
    4. 基于@Bean注解
    
8、纯注解版AOP编程
  1. 搭建环境

    1. 应用配置Bean
    2. 注解扫描
    
  2. 开发步骤

    1. 原始对象
    	@Service
    	public class UserServiceImpl implements userService{
    	
    	}
    2. 创建切面类(额外功能、切入点、组装切面)
    
    3. Spring的配置文件中
    	<aop:aspectj-autoproxy />   ----> EnableAspectjAuroProxy
    
  3. 注解AOP细节分析

    1. 代理创建方式的切换  JDK  Cglib
    <aop:aspectj-autoproxy  proxy-target-class=true|false />
    @EnableAspectjAutoproxy(proxyTargetClass)
    2. SpringBoot  AOP的开发方式
    	@EnableAspectjAutoproxy  已经默认设置好了
    	1. 原始对象
    	2.创建切面类
    	
    Spring AOP 代理默认实现是JDK
    SpringBoot AOP 代理默认实现是Cglib
    
9、Spring框架中YML的使用
  1. 什么是YML

    YML(YAML)是一种新形式的配置文件,比XML更简单,比Properties更强大
    
  2. Properties进行配置问题

    1. Properties表达过于繁琐,无法表达数据的内在联系
    2. Properties无法表达对象,集合类选
    
  3. YML语法简介

    1. 定义yml文件
    	xxx.yml   xxx.yaml
    2. 语法
    	1. 基本语法
    		name:sun
    		password:123455
    	2.对象概念
    		account:
    			id:1
    			password:123456
    	3. 定义集合
    		 service
    		 	- 11111
    		 	- 22222
    
  4. Spring与YML集成思路的分析

    1. 准备yml配置文件
    	init.yml
    2. 读取yml转换成Properties
    	YamlPropertiesFactoryBean.setResources(yml的配置路径) new ClassPathResource();
    	YamlPropertiesFactoryBean.getObject() ---> Properties
    3. 应用PropertySourcePlaceHolderConfigurer
    	PropertySourcePlaceholderConfigurer.setProperties();
    4. 类中@Value注解  注入
    
  5. Spring与YML集成编码

  • 环境搭建

    <!-- https://mvnrepository.com/artifact/org.yaml/snakeyaml -->
    <dependency>
        <groupId>org.yaml</groupId>
        <artifactId>snakeyaml</artifactId>
        <version>1.26</version>
    </dependency>
    最低版本1.18
    
  • 编码

    1. 准备yml配置文件
    2. 配置Bean中操作,完成YAML读取与PropertySourcePlacehlderConfigure的创建
    	@Bean
    	public PropertySourcePlaceholderConfigurer congifurer(){
    		YamlPropertiesFactoryBean ymlPropertiesFactoryBean = new YamlPropertiesFactoryBean();
    		ymlPropertiesFactoryBean.setResources(new ClassPathReource("init.yml));
    		Properties properties = ymlPropertiesFactoryBean.getObject();
    		
    		PropertySourcesPlaceholderConfigurer configurer = new PropertySourcesPlaceholderConfigurer();
    		configurer.setProperties(properties);
    		return configurer;
    	}
    3. 类 加入 @Value注解
    
  1. Spring与YML集成的问题

    1. 集合处理的问题
    	SpringEL表达式解决
    	@Value("#{'${list}'.split(',')}")
    2. 对象类型的YAML进行配置时,过于繁琐
    	@Value("$(account.name)")
    
    SpringBoot  @ConfigurationProperties