Java | Spring框架学习笔记--(5)注解编程

系列文章:
Java | Spring框架学习笔记–(1)工厂
Java | Spring框架学习笔记–(2)AOP
Java | Spring框架学习笔记–(3)持久层整合
Java | Spring框架学习笔记–(4)MVC框架整合
Java | Spring框架学习笔记–(5)注解编程

注解编程

注解编程:指的是在类或者方法上加入特定的注解(@XXX)来完成特定功能的开发。

为什么要注解编程?

  1. 注解开发方便,代码简洁,开发速度大大提高
  2. Spring的开发潮流(从2.x版本引入注解,3.x版本完善,到SpringBoot普及)

环境准备

首先要在maven的pom包中引入Spring的相关jar包(这个不用说),然后再applicationContext.xml中加入

<context:component-scan base-package="com.prince" />

这个标签的作用是开启注解编程,并告诉Spring需要搜索的包。

基础注解

对象创建相关注解

@Component

作用:替换掉原有Spring配置文件中的bean标签
用法:直接在类前面加上该注解

@Component
public class User {

其中

  • id属性,默认值是类名首字母小写(如User -> user,UserDao -> userDao),可以通过value属性来指定
  • class属性:通过反射获取

测试:

@Test
public void test(){
    ApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicaationContext.xml");
    User user = applicationContext.getBean("user", User.class);
    System.out.println("user = " + user);
}

衍生注解:(效果完全一样,只是名字不同而已,功能没有区别)

@Repository
@Service
@Controller
@Scope

作用:控制简单对象的创建次数(等同于原来bean标签的scope属性)

<bean id="" class="" scope="singleton|prototype"></bean>

用法:直接在类前面加上注解

@Component
@Scope("singleton")
public class User {

注意:默认值singleton

@Lazy

作用:延迟创建单实例对象(替换掉原来bean标签的lazy属性)

<bean id="" class="" lazy="false"></bean>

用法:在类前面加上该注解,代表延迟加载,只在获取该对象的时候才会创建。

@Component
@Lazy
public class User {

与生命周期相关的注解

使用到两个注解:

  1. 初始化相关方法:@PostConstruct
  2. 销毁方法:@PreDestroy

用法:直接在类的对应方法前面加上该注解即可

(注意导入javax的包,这两个注解是java提供的而不是spring)

import org.springframework.stereotype.Component;
import javax.annotation.PostConstruct;
import javax.annotation.PreDestroy;


@Component
public class Product {

    @PostConstruct
    public void myInit(){
        System.out.println("Product.myInit");
    }

    @PreDestroy
    public void myDestroy(){
        System.out.println("Product.myDestroy");
    }
}

测试:

@Test
public void test2(){
    ClassPathXmlApplicationContext applicationContext = new ClassPathXmlApplicationContext("applicaationContext.xml");//工厂创建,对象创建,调用初始化方法
    applicationContext.close(); //工厂关闭,对象销毁,调用销毁方法
}

注意:这两个注解不是Spring提供的,而是JSR(JAVAEE规范)520,这再一次地验证,通过注解实现接口的契约型。

注入相关注解

@AutoWired

作用:把这个注解加在成员变量或者setter方法上,Spring就会自动根据 类型 进行注入。这个注解主要用于 用户自定义类型 的注入

比如在UserService里注入UserDao:

@Repository
public class UserDaoImpl implements UserDao {
    @Override
    public void insert() {
        System.out.println("UserDaoImpl.insert");
    }
}
@Service
public class UserService {

    @Autowired
    private UserDao userDao;

    public UserService(UserDao userDao) {
        this.userDao = userDao;
    }

    public UserDao getUserDao() {
        return userDao;
    }

    public void setUserDao(UserDao userDao) {
        this.userDao = userDao;
    }
}

细节:

  • 如果想根据id注入,而不是类型,可以和@Qualifier注解配合使用

    @Autowired
    @Qualifier("userDaoImpl")
    private UserDao userDao;
    
  • JavaEE规范JSR250中有类似功能的注解@Resource(name = ""),基于id值进行注入,等同于@Autowired@Qualifier的结合

    //import javax.annotation.Resource;
    @Resource(name = "userDaoImpl")
    private UserDao userDao;
    

    当不指定name属性的时候,将会按照类型进行注入

  • JavaEE规范的JSR330中还有一个注解@Inject,作用和@Autowired完全一致,使用时需要导入依赖:

    <dependency>
        <groupId>javax.inject</groupId>
        <artifactId>javax.inject</artifactId>
        <version>1</version>
    </dependency>
    
@Value

这个注解主要用于JDK内置类型的注入,使用方法:直接在成员变量前面加上注解。

@Component
public class User {
    @Value("123456")
    private Integer id;
    @Value("abcabc")
    private String username;

为了解耦合,可以把Value里的值都抽取到一个properties文件里,然后让Spring读取这个配置文件来进行注入(配置文件参数化)。

id = 123456
username = abcabc

在Spring 的applicationContext.xml中配置,读取properties文件

<context:property-placeholder location="classpath:/user.properties" />

然后@Value注解中使用EL表达式:

@Component
public class User {
    @Value("${id}")
    private Integer id;
    @Value("${username}")
    private String username;

注意:

  • @Value注解不能放在静态成员变量前面,如果放,也是注入失败。

  • @Value + Properties的注入方式不支持集合类型,如果需要,需要用到Spring提供的新配置形式 YAMLYML

  • 可以使用@PropertySource注解来代替xml中的配置<context:property-placeholder location="classpath:/user.properties" />

    @Component
    @PropertySource("classpath:/user.properties")
    public class User {
        @Value("${id}")
        private Integer id;
        @Value("${username}")
        private String username;
    

注解扫描

开启注解扫描:自动扫描指定包及其子包下的所有类。

<context:component-scan base-package="com.prince" />

排除方式

context:component-scan标签内部嵌套context:exclude-filter标签即可!

<context:component-scan base-package="com.prince" >
        <context:exclude-filter type="" expression=""/>
</context:component-scan>

在这里插入图片描述

type属性共有5中取值:

  1. aspectj
    通过切入点表达式(类切入点 和 包切入点)进行排除。

    <!-- 排除com.prince.service包及其子包下的所有类 -->
    <context:exclude-filter type="aspectj" expression="com.prince.service..*"/>
    <!-- 排除任意包下所有名为User的类 -->
    <context:exclude-filter type="aspectj" expression="*..User"/>
    

    注意:使用需要导入aspect的相关依赖

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.9.4</version>
    </dependency>
    
  2. annotation
    排除使用指定注解的类

    <!-- 排除使用@Service注解的类 -->
    <context:exclude-filter type="annotation" expression="org.springframework.stereotype.Service"/>
    
  3. assignable
    排除指定类型

    <!-- 排除User类 -->
    <context:exclude-filter type="assignable" expression="com.prince.bean.User"/>
    
  4. regex:正则 custom:自定义
    这两个使用得比较少

包含方式

和排除方式一样,这个嵌套的是context:include-filter

<context:component-scan base-package="com.prince" use-default-filters="false">
    <context:include-filter type="" expression=""/>
</context:component-scan>

其中type和expression和排除方式是一模一样的。

主要是包含方式要指定use-default-filters="false",表示让Spring默认的注解扫描失效,只有指定了这个注解的值为false,Spring才会只扫描context:include-filter中配置的类,否则Spring还是会对base-package指定的包及其子包全部扫描进去。

高级注解

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

配置类

不再使用ApplicationContext.xml的配置文件,取而代之的是由@Configuration标注的配置类。

@Configuration
public class AppConfig {
}

在这里插入图片描述

创建ApplicationContext类的时候,不再使用ClassPathApplicationContext,而是使用AnnotationConfigApplicationContext

//使用AppConfig这个配置类
ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig.class);
//扫描com.prince.config包及其子包下所有的配置类
ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.prince.config");

@Configuration注解的本质:也是@Component的衍生注解:

在这里插入图片描述

日志

不推荐log4j,使用logback作为日志框架:

  1. 先引入logback相关依赖

    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>slf4j-api</artifactId>
        <version>1.7.30</version>
    </dependency>
    
    <dependency>
        <groupId>org.slf4j</groupId>
        <artifactId>jcl-over-slf4j</artifactId>
        <version>1.7.30</version>
    </dependency>
    
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-classic</artifactId>
        <version>1.2.3</version>
    </dependency>
    
    <dependency>
        <groupId>ch.qos.logback</groupId>
        <artifactId>logback-core</artifactId>
        <version>1.2.3</version>
    </dependency>
    
    <dependency>
        <groupId>org.logback-extensions</groupId>
        <artifactId>logback-ext-spring</artifactId>
        <version>0.1.5</version>
    </dependency>
    
  2. 引入logback.xml配置文件

    <?xml version="1.0" encoding="UTF-8"?>
    <configuration>
        <!-- 控制台输出 -->
        <appender name="STDOUT"
                  class="ch.qos.logback.core.ConsoleAppender">
            <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>
    

@Bean注解的使用

@Bean注解在配置bean中使用,等同于XML配置中的bean标签

@Bean注解加到一个方法中,返回值是要创建的对象的类型,方法名就是id值,再把对象创建的代码放到方法体中即可!

在这里插入图片描述

  • 创建简单对象

    @Bean
    public User user(){
        User user = new User();
        user.setId(10086);
        user.setUsername("prince");
        return user;
    }
    
  • 创建复杂对象

    @Bean
    public Connection connection(){
        try {
            Class.forName("com.mysql.jdbc.Driver");
            Connection conn = DriverManager.getConnection("jdbc:mysql:///mydata","root","root");
            return conn;
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }
    
  • 使用FactoryBean创建复杂对象(不常用)

    import org.springframework.beans.factory.FactoryBean;
    
    import java.sql.Connection;
    import java.sql.DriverManager;
    
    public class ConnectFactoryBean implements FactoryBean<Connection> {
        @Override
        public Connection getObject() throws Exception {
            Class.forName("com.mysql.jdbc.Driver");
            Connection conn = DriverManager.getConnection("jdbc:mysql:///mydata","root","root");
            return conn;
        }
    
        @Override
        public Class<?> getObjectType() {
            return Connection.class;
        }
    
        @Override
        public boolean isSingleton() {
            return false;
        }
    }
    

    在配置类中直接引用这个ConnectFactoryBean的getObject即可

    @Bean
    public Connection connection1(){
        Connection connection = null;
        try {
            connection = new ConnectFactoryBean().getObject();
        } catch (Exception e) {
            e.printStackTrace();
        }
        return connection;
    }
    

细节:

  • 自定义id值,默认是取方法名作为默认的id值,也可以给Bean注解加上参数作为id值

    @Bean("u")		//创建一个对象,id值是u
    public User user(){
    
  • 控制对象创建次数

    @Bean("u")
    @Scope("prototype")
    public User user(){
    

@Bean注解的注入

用户自定义类型

原来XML中的配置是这样的:

<bean id="userDao" class="com.prince.dao.UserDaoImpl" />
<bean id="userService" class="com.prince.service.UserServiceImpl">
    <property name="userDao" ref="userDao" />
</bean>

换成注解之后是这样的:

  • UserDao对象的创建:

    @Bean
    public UserDao userDao(){
        return new UserDaoImpl();
    }
    
  • UserService的创建,由于需要依赖注入上面的UserDao,所以要先获取到我们创建的UserDao再通过setter注入,有两种方法:

    1. 直接把UserDao当成函数的参数传进去

      @Bean
      public UserService userService(UserDao userDao){
          UserServiceImpl userService = new UserServiceImpl();
          userService.setUserDao(userDao);
          return userService;
      }
      
    2. 第二种方法更为简单,不需要传参数,直接在调用setUserDao的时候把函数传进去

      @Bean
      public UserService userService(){
          UserServiceImpl userService = new UserServiceImpl();
          userService.setUserDao(userDao());
          return userService;
      }
      
JDK类型
@Bean
public User user(){
    User user = new User();
    user.setId(10086);
    user.setUsername("prince");
    return user;
}

细节:可以配合@PropertySource@Value注解,把要注入的值放到配置文件中,进行解耦合

@Configuration
@PropertySource("classpath:/user.properties")
public class AppConfig {
    @Value("${id}")
    private Integer id;
    @Value("${name}")
    private String username;

    @Bean
    public User user(){
        User user = new User();
        user.setId(id);
        user.setUsername(username);
        return user;
    }

@ComponentScan

注解扫描注解

@Configuration
@ComponentScan(basePackages = "com.prince")
public class AppConfig1 {

排除策略:(和XML的类似)

@Configuration
@ComponentScan(basePackages = "com.prince",
        excludeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {UserService.class}),
                @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = {"com.prince.dao..*"})
        }
)
public class AppConfig2 {
}

包含策略:(和XML的一样,也要先useDefaultFilters = false,取消默认的扫描策略)

@Configuration
@ComponentScan(basePackages = "com.prince",
        useDefaultFilters = false,
        includeFilters = {@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, value = {UserService.class}),
                @ComponentScan.Filter(type = FilterType.ASPECTJ, pattern = {"com.prince.dao..*"})
        }
)
public class AppConfig2 {
}

多配置创建对象的优先级

配置Bean创建对象的优先级:@Component注解创建的对象 < @Bean注解创建的对象 < XML中bean标签创建的对象

高优先级可以覆盖低优先级(覆盖的前提是对象的ID值保持一致!

怎么同时使用配置类和配置文件?加入@ImportResource注解。

@Configuration
@ImportResource("classpath:/applicationContext.xml")
public class AppConfig2 {
}

为了解决耦合问题,比如前面的UserDao

@Bean
public UserDao userDao(){
    return new UserDaoImpl();
}

当以后如果需要更改UserDao的实现类,不再是UserDaoImpl,需要改成新的UserDaoImplNew的时候,就不需要修改源代码,直接用配置覆盖的方式,重新在XML中配置即可:

<bean id="userDao" class="com.prince.dao.UserDaoImplNew" />

这样子获取id为userDao的对象的时候,获取的是UserDaoImplNew而不是UserDaoImpl

多配置信息的整合

  • 为什么会有多个配置信息?
    拆分多个配置类的开发,是一种模块化开发的形式,也体现了面向对象各司其职的设计思想。

  • 多配置信息整合的方式

    1. 多个配置类的整合
    2. 配置类和@Component相关注解的整合
    3. 配置类和XML配置文件的整合
  • 整合多种配置需要关注的要点

    1. 如何使多配置的信息汇总成一个整体
    2. 如何实现跨配置的注入(一个配置类创建的对象中注入另一个配置类创建的对象)
多个配置类的整合
  1. 在创建ApplicationContext的时候扫描整个包下的所有配置类

    //扫描com.prince.config包及其子包下所有的配置类
    ApplicationContext applicationContext = new AnnotationConfigApplicationContext("com.prince.config");
    
  2. 再其中一个配置类中用@Import注解来引入另一个配置类

    @Configuration
    @Import(AppConfig2.class)
    public class AppConfig1 {
    

    然后再创建ApplicationContext的时候,只需要传入AppConfig1.class就可以同时读取两个配置类的信息

    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig1.class);
    

    这样子等同于XML中的配置:

    <import resource="classpath:applicationContext1.xml" />
    
  3. 在AnnotationConfigApplicationContext中指定多个配置类(可变参数)

    ApplicationContext applicationContext = new AnnotationConfigApplicationContext(AppConfig1.class, AppConfig2.class);
    

跨配置类的对象注入:

@Configuration
@Import(AppConfig2.class)
public class AppConfig1 {
    @Bean
    public UserDao userDao(){
        return new UserDaoImpl();
    }
}
//===================================================
//AppConfig2中创建的UserService,需要注入AppConfig1中创建的UserDao,
//只需要在AppConfig2中创建一个成员变量,并加上@Autowired注解即可。
//===================================================
@Configuration
public class AppConfig2 {

    @Autowired
    private UserDao userDao;

    @Bean
    public UserService userService() {
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao);
        return userService;
    }
}

**在应⽤配置类的过程中,不管使⽤哪种⽅式进⾏配置信息的汇总,其操作⽅式都是通过成员变量加⼊@Autowired注解完成。 **

配置类和@Component相关注解的整合

使用@ComponentScan注解来扫描所有@Component创建的对象,注入的时候也是采用@Autowired的方式

@Configuration
@ComponentScan("com.prince.dao")
public class AppConfig2 {

    @Autowired
    private UserDao userDao;

    @Bean
    public UserService userService() {
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao);
        return userService;
    }
}
@Component
public class UserDaoImpl implements UserDao{
配置类与配置文件的的整合

使用@ImportResource来引入XML配置文件

@Configuration
@ImportResource("classpath:applicationContext.xml")
public class AppConfig2 {

    @Autowired
    private UserDao userDao;

    @Bean
    public UserService userService() {
        UserServiceImpl userService = new UserServiceImpl();
        userService.setUserDao(userDao);
        return userService;
    }
}
<bean id="userDao" class="com.prince.dao.UserDaoImpl" />

纯注解版AOP编程

import org.springframework.stereotype.Service;

@Service
public class UserServiceImpl {
    public void register(){
        System.out.println("UserServiceImpl.register");
    }

}
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.springframework.stereotype.Component;

@Aspect //切面类
@Component
public class MyAround {

    @Around("execution(* com.prince.aop..*(..))")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable{
        System.out.println("====================log=====================");
        Object ret = joinPoint.proceed();
        return ret;
    }
}

@Configuration
@EnableAspectJAutoProxy //等同于<aop:aspectj-autoproxy />
@ComponentScan("com.prince.aop")
public class AopConfig {
}

细节分析:

  1. 代理创建模式的切换(JDK / Cglib)
    原XML中是这样子设置的

    <aop:config proxy-target-class="true">
    </aop:config>
    <!--或者-->
    <aop:aspectj-autoproxy proxy-target-class="true" />
    

    注解的方式:

    @EnableAspectJAutoProxy(proxyTargetClass = true)
    
  2. SpringBoot中AOP的开发方式,只需要前两步(原始对象、切面类),不需要@EnableAspectJAutoProxy,已经默认设置好了。而且SpringAOP的默认代理实现是JDK,而SpringBoot AOP的默认实现是CGlib。

纯注解版Spring+Mybatis整合

整合
  1. druid连接池
    XML 中的配置:

    <bean class="com.alibaba.druid.pool.DruidDataSource" id="dataSource">
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
     <property name="url" value="jdbc:mysql://localhost:3306/mydata"/>
        <property name="username" value="root" />
     <property name="password" value="root" />
    </bean>
    

    配置类中的配置:

    @Bean
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/mydata");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }
    
  2. SqlSessionFactoryBean
    XML 中的配置:

    <!--配置SqlSessionFactoryBean-->
    <bean class="org.mybatis.spring.SqlSessionFactoryBean" id="factoryBean">
     <!--指定DataSource数据库连接池-->
        <property name="dataSource" ref="dataSource" />
     <!--给实体类设置别名-->
        <property name="typeAliasesPackage" value="com.prince.entity" />
        <!--设置mapper.xml的文件路径-->
        <property name="mapperLocations">
         <list>
                <value>mapper/*Mapper.xml</value>
            </list>
        </property>
    </bean>
    

    配置类中的配置:(注意需要注入上一步创建的DataSource对象)

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);  //注入DataSource
        sqlSessionFactoryBean.setTypeAliasesPackage("com.prince.mybatis");
        sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("mapper/UserDaoMapper.xml"));
        return sqlSessionFactoryBean;
    }
    
  3. MapperScannerConfigure
    XML 中的配置:

    <!--配置MapperScannerConfigurer-->
    <bean class="org.mybatis.spring.mapper.MapperScannerConfigurer" id="configurer">
    <!--SqlSessionFactoryBean-->
       <property name="sqlSessionFactoryBeanName" value="factoryBean" />
    <!--指定Dao接口所在的包-->
       <property name="basePackage" value="com.prince.dao" />
    
    </bean>
    

    配置类中的配置:
    这个我们不需要专门去创建一个MapperScannerConfigurer,Spring已经为我们提供了一个注解。直接把这个注解加到配置类上面就行了。

    @Configuration
    @ComponentScan("com.prince.mybatis")
    @MapperScan(basePackages = {"com.prince.mybatis.dao"})
    public class MybatisConfig {
    

    @MapperScan注解只需要指定一个basePackages,表示Dao接口存放的位置。不需要专门指定sqlSessionFactoryBeanName,因为把注解加到类上,Spring还是可以扫描到这个类里创建的SqlSessionFactoryBean,而且创建SqlSessionFactoryBean的时候id值是可以任意取的。

完整代码:

@Configuration
@ComponentScan("com.prince.mybatis")
@MapperScan(basePackages = {"com.prince.mybatis.dao"})
public class MybatisConfig {

    @Bean
    public DataSource dataSource(){
        DruidDataSource dataSource = new DruidDataSource();
        dataSource.setDriverClassName("com.mysql.jdbc.Driver");
        dataSource.setUrl("jdbc:mysql://localhost:3306/mydata");
        dataSource.setUsername("root");
        dataSource.setPassword("root");
        return dataSource;
    }

    @Bean
    public SqlSessionFactoryBean sqlSessionFactoryBean(DataSource dataSource){
        SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
        sqlSessionFactoryBean.setDataSource(dataSource);  //注入DataSource
        sqlSessionFactoryBean.setTypeAliasesPackage("com.prince.mybatis");
        sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("mapper/UserDaoMapper.xml"));
        return sqlSessionFactoryBean;
    }

}
细节
  • MapperLocations编码时通配的写法
    在XML配置中,MapperLocations是可以直接写通配符的:

    <property name="mapperLocations">
        <list>
            <value>mapper/*Mapper.xml</value>
        </list>
    </property>
    

    而注解配置中,这样子配置是会报错的

    sqlSessionFactoryBean.setMapperLocations(new ClassPathResource("mapper/*Mapper.xml"));
    

    解决办法:使用 ResourcePatternResolver ( PathMatchingResourcePatternResolver )

    ResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
    Resource[] resources = resolver.getResources("mapper/*Mapper.xml");
    sqlSessionFactoryBean.setMapperLocations(resources);
    

    因为sqlSessionFactoryBean.setMapperLocations的参数是Resource类型的可变参数,所以可以直接传入一个数组。

  • 配置类中数据的耦合问题
    解决:数据库的DriverClassName,URL,username,password可以抽取到一个properties配置文件中,然后再利用@PropertySource@Value注解。

事务

原来的XML配置版本:

<bean class="org.springframework.jdbc.datasource.DataSourceTransactionManager" id="dataSourceTransactionManager">
    <!--传入dataSource数据库连接池-->
    <property name="dataSource" ref="dataSource"/>
</bean>

<!--组装切面-->
<tx:annotation-driven transaction-manager="dataSourceTransactionManager" />

<bean class="com.prince.service.UserServiceImpl" id="userService">
    <!--Spring与Mybatis整合的时候会创建一个UserDao,直接把这个UserDao注入即可-->
    <property name="userDao" ref="userDao"/>
</bean>

注解配置版本:

  • TransactionManager

    @Bean
    public DataSourceTransactionManager dataSourceTransactionManager(){
        DataSourceTransactionManager dataSourceTransactionManager = new DataSourceTransactionManager();
        dataSourceTransactionManager.setDataSource(dataSource());
        return dataSourceTransactionManager;
    }
    
  • tx:annotation-driven:

    @EnableTransactionManagement(proxyTargetClass = true)
    public class MybatisConfig {
    

    (注解一样不需要手动输入TransactionManager的id值,因为注解加到类上,Spring可以扫描这个类的所有TransactionManager)
    有一个bug,使用JDK动态代理的时候会报错,我也不知道是什么原因,用cglib没问题,所有我就加上了proxyTargetClass = true

  • UserService:

    @Service
    @Transactional
    public class UserServiceImpl implements UserService{
        @Autowired
        UserDao userDao;
    
        @Override
        public void insert(User user) {
            userDao.insert(user);
        }
    
        @Override
        public User login(String username, String password) {
            return userDao.login(username,password);
        }
    }
    

    (使用了@Service@Autowired还完成对象创建)

YAML

YML(YAML)是⼀种新形式的配置⽂件,比XML更简单,比Properties更强大。

Properties配置问题:

  1. 表达过于繁琐,无法表达数据的内在联系。
  2. 无法表达对象、集合类型

语法

  1. 基本语法(key: value的格式,注意冒号后面需要留一个空格!

    name: prince
    password: 123456
    
  2. 对象(注意缩进!

    person: 
       name: prince
       password: 123456
    
  3. 集合(注意缩进!!每一个值以-开头,并留一个空格

      list:
        - 111111
        - 222222
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值