正在连接海拉鲁...

Spring

概述

  1. Spring是一个开源框架,是为了解决企业级应用开发的复杂性而设计的
  2. Spring最根本的使命:全方位简化Java开发
  3. 核心思想:
    • ioC:控制反转,就是把依赖对象创建的控制权交给第三方来处理
    • DI:依赖注入,组件之间的依赖关系在程序运行期间由第三方动态地注入依赖

使用

  1. 添加Spring依赖

    <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-context</artifactId>
                <version>5.3.22</version>
            </dependency>
  2. 添加Spring容器的配置类,并添加组件

    //作为Spring容器的配置类,告诉Spring容器中管理哪些组件
    @Configuration
    public class AppConfig {
        //组件
        @Bean
        public EmpDao empDao(){
            return new OracleEmpDaoImpl();//返回接口的实现类
        }
    
    }
  3. 测试(创建一个Spring容器,并得到组件)

    //从Spring的容器中得到一个组件(EmpDao)
       @Test
       public void getEmpDao(){
           //得到Spring容器
           ApplicationContext context = new AnnotationConfigApplicationContext(AppConfig.class);
       
           //得到容器中的组件
           EmpDao contextBean = context.getBean(EmpDao.class);
           contextBean.insert();
       }
    • ApplicationContext:是一个Spring接口,负责管理应用的各个方面,如Bean的生命周期
    • AnnotationConfigApplicationContext:是ApplicationContext接口的一个实现,用于从一个带有@Configuration注解的Java类来加载Spring应用上下文
  4. 得到组件

    • 根据类型得到

      EmpDao empDao = c.getBean(EmpDao.class);
    • 根据名称得到

      EmpDao empDao = c.getBean("oracleEmpDao")
          
          
      //配置类中
      @Bean(name = "oracleEmpDao")//组件默认为方法名
          public EmpDao empDao(){
              return new OracleEmpDaoImpl();//返回接口的实现类
          } 
  5. 组件装配

    @Bean
        public EmpService empService(){
            EmpServiceImpl empService = new EmpServiceImpl();
            empService.setEmpDao(empDao());//DI:依赖注入,属性注入
            return empService;
        }
    

    构造注入:通过构造参数,注入依赖

    @Bean
    public EmpService empService(){
        EmpServiceImpl empService = new EmpServiceImpl(mySqlEmpDao());
        return empService;
    }

    依赖注入的三种方式

    • 属性注入
    • 构造注入
    • 接口注入(Spring不支持)

Bean说明

  1. @Scope:作用域(单例:singleton(默认的),prototype(原生的))

    @Bean
    @Scope("prototype")
        public EmpService empService(){
            EmpServiceImpl empService = new EmpServiceImpl();
            empService.setEmpDao(empDao());
            return empService;
        }
    
    //单例指的是每一次调用只给同一个对象
    //原生多例指的是每次调用都新创建一个对象
  2. @Lazy:懒加载(延时加载,在getBean()的时候再加载),默认值@Lazy(false),容器启动的时候创建组件

    • 注意:在@Scope为prototype的时候,一定是懒加载的,在组件单例的情况下设置@Lazy才有意义的

      @Bean
          @Lazy(true)//懒加载
          public EmpService empService(){
              EmpServiceImpl empService = new EmpServiceImpl();
              empService.setEmpDao(empDao());
              return empService;
          }
  3. 组件扫描

    @ComponentScan(basePackages = {"com.neu.dao","com.neu.service"})
    public class AppConfig {}
    @Component//组件名默认是类名首字母小写
    public class OracleEmpDaoImpl implements EmpDao {
        @Override
        public int insert() {
            System.out.println("执行了Oracle的Emp添加操作");
            return 0;
        }
    }
    
    
    @Component("oracleEmpDao")//参数是组件的别名
    public class OracleEmpDaoImpl implements EmpDao {
        @Override
        public int insert() {
            System.out.println("执行了Oracle的Emp添加操作");
            return 0;
        }
    }
    • Component:用于定义一个Bean,Spring容器将负责这个Bean的生命周期,value属性允许你为这个Bean设置一个名称
  4. 自动装配

    @Autowired//自动装配
        public void setEmpDao(EmpDao empDao){
            this.empDao = empDao;
        }
    • @Autowired注解用于实现依赖注入,也就是自动装配,意味着Spring容器会自动解析并注入所需要的依赖,默认@Autowired按照类型来进行自动装配,可以将注解加到构造函数上,setter方法或者字段上,不推荐在字段上添加该注解,因为破坏了封装性
  5. 解决自动装配冲突(使用组件名装配)

    @Component("EmpService")
    public class EmpServiceImpl implements EmpService {
        private EmpDao empDao;
        @Autowired//自动装配
        @Qualifier("mySQLEmpDap")//使用组件名装配
        public void setEmpDao(EmpDao empDao){
            this.empDao = empDao;
        }
        @Override
        public int insert() {
            empDao.insert();
            return 0;
        }
    }
    • @Qualifier:用于消除自动装配的歧义

使用Spring的测试模块

  1. 添加依赖

    <spring.version>5.3.22</spring.version>
    
    <dependency>
                <groupId>org.springframework</groupId>
                <artifactId>spring-test</artifactId>
                <version>${spring.version}</version>
    </dependency>
  2. 测试

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = AppConfig.class)
    public class EmpDaoTest2 {
    
        private EmpDao empDao;
        @Autowired()
        @Qualifier("mySQLEmpDap")
        public void setEmpDao(EmpDao empDao){
            this.empDao = empDao;
        }
    
        @Test
        public void insert(){
            empDao.insert();
        }
    }
    • @RunWith:是JUnit的一个注解,用于定义自定义的测试运行器
      • SpringJUnit4ClassRunner.class是Spring提供的一个测试运行器,它拓展了JUnit的功能,使得测试类能够在Spring的应用上下文环境下执行(使得当前测试类变为Spring容器的组件)
    • @ContextConfiguration:用于定义如何引导Spring应用程序上下文(Spring容器)

AOP

  1. 定义:面向切面编程,模块化横切关注点(把相同的代码加入到关注的方法上)

  2. 导入包

    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjweaver</artifactId>
        <version>1.7.3</version>
    </dependency>
    <dependency>
        <groupId>org.aspectj</groupId>
        <artifactId>aspectjrt</artifactId>
        <version>1.7.3</version>
    </dependency>
  3. 定义一个类,实现切面的功能

    @Configuration
    @Component
    @Aspect//切面
    @EnableAspectJAutoProxy//开启切面自动的代理
    public class AOPUtil {
        //切入点,加入相同代码的一组关注点(连接点)
        @Pointcut("execution(* com.neu.dao.*.*(..))")
        public void pointcut(){
    
        }
        //通知:加入的代码
        @Around("pointcut()")
        public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
            long startTime = System.nanoTime();
            //调用代理的方法
            Object proceed = joinPoint.proceed();
    
            long endTime = System.nanoTime();
    
            System.out.println("insert方法的执行时间是:"+(endTime-startTime)+"纳秒");
    
            return proceed;
        }
    }
    • 连接点(joinPoint):程序执行过程中特定点(Spring中的方法)
    • 通知(Advice):在特定连接点加入的代码
    • 切入点(pointCut):加入相同通知的一组连接点
    • 切面(Aspect):通知与切入点的组合
  4. 前置通知

    @Before("pointcut()")
       public void before(JoinPoint joinPoint){
           String signature = joinPoint.getSignature().getName();
           String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
           System.out.println(declaringTypeName+"中"+signature+"方法开始执行时间是:"+new Date());
       }
  5. 返回后通知:执行了return语句后执行的代码

    @AfterReturning("pointcut()")
        public void afterReturning(JoinPoint joinPoint){
            String signature = joinPoint.getSignature().getName();
            String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
            System.out.println(declaringTypeName+"中"+signature+"方法结束时间是:"+new Date());
        }
  6. 异常通知

    @AfterThrowing("pointcut()")
        public void afterThrowing(JoinPoint joinPoint){
            String signature = joinPoint.getSignature().getName();
            String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
            System.out.println(declaringTypeName+"中"+signature+"方法异常发生时间是:"+new Date());
        }
  7. 最终通知

    @After("pointcut()")
        public void after(JoinPoint joinPoint){
            String signature = joinPoint.getSignature().getName();
            String declaringTypeName = joinPoint.getSignature().getDeclaringTypeName();
            System.out.println(declaringTypeName+"中"+signature+"方法最终结束时间是:"+new Date());
        }
  8. 环绕通知

    @Around("pointcut()")
       public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
           long startTime = System.nanoTime();
           //调用代理的方法
           Object proceed = joinPoint.proceed();
       
           long endTime = System.nanoTime();
       
           System.out.println("insert方法的执行时间是:"+(endTime-startTime)+"纳秒");
       
           return proceed;
       }
  9. AOP用途:日志、权限管理、事务

Spring对数据源的支持

  1. 导入连接池及数据库驱动

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
        <version>8.0.22</version>
    </dependency>
    <dependency>
        <groupId>commons-dbcp</groupId>
        <artifactId>commons-dbcp</artifactId>
        <version>1.4</version>
    </dependency>
  2. 定义一个属性文件(db.properties),在其中配置数据库连接池需要的参数

    jdbc.username=root
    jdbc.password=root
    jdbc.url=jdbc:mysql://localhost:3306/neusoft?useUnicode=true&characterEncoding=utf8&serverTimezone=Asia/Shanghai
    jdbc.driverClassName=com.mysql.cj.jdbc.Driver
    
    jdbc.maxActive=20
    jdbc.maxWait=2000
    jdbc.maxIdle=5
  3. 定义一个配置类,读取数据库连接属性文件

    @Configuration
    @PropertySource("classpath:db.properties")
    public class DBConfig {
        @Value("${jdbc.username}")
        private String username;
        @Value("${jdbc.password}")
        private String password;
        @Value("${jdbc.url}")
        private String url;
        @Value("${jdbc.driverClassName}")
        private String driverClassName;
        @Value("${jdbc.maxActive}")
        private Integer maxActive;
        @Value("${jdbc.maxWait}")
        private Integer maxWait;
        @Value("${jdbc.maxIdle}")
        private Integer maxIdle;
        @Bean
        public DataSource dataSource(){
            BasicDataSource bs = new BasicDataSource();
            bs.setUsername(username);
            bs.setPassword(password);
            bs.setUrl(url);
            bs.setDriverClassName(driverClassName);
            bs.setMaxActive(maxActive);
            bs.setMaxWait(maxWait);
            bs.setMaxIdle(maxIdle);
    
            return bs;
        }
    
    }
  4. 测试

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {AppConfig.class, DBConfig.class})
    public class EmpDaoTest2 {
    
        private DataSource dataSource;
    
        @Autowired
        public void setDataSource(DataSource dataSource){
            this.dataSource = dataSource;
        }
    
        @Test
        public void testDataSource() throws SQLException {
            Connection connection = dataSource.getConnection();
            connection.close();
        }
    }

Spring与MyBatis的集成

  1. 导入依赖jar包

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-jdbc</artifactId>
        <version>4.3.8.RELEASE</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis-spring</artifactId>
        <version>1.3.1</version>
    </dependency>
    <dependency>
        <groupId>org.mybatis</groupId>
        <artifactId>mybatis</artifactId>
        <version>3.5.6</version>
    </dependency>
  2. 配置SqlSessionFactory

    @Configuration
    @MapperScan("com.neu.mapper")
    public class MyBatisConfig {
        @Bean
        public SqlSessionFactory sqlSessionFactory(DataSource dataSource) throws Exception {
            SqlSessionFactoryBean sqlSessionFactoryBean = new SqlSessionFactoryBean();
            //设置数据源
            sqlSessionFactoryBean.setDataSource(dataSource);
            
            return sqlSessionFactoryBean.getObject();
        }
    
    }
  3. 创建Mapper接口和对应的xml文件

  4. 测试

    @RunWith(SpringJUnit4ClassRunner.class)
    @ContextConfiguration(classes = {DBConfig.class, MyBatisConfig.class})
    public class DpetMapperTest {
        private DeptMapper deptMapper;
        
    
        @Autowired
        public void setDeptMapper(DeptMapper deptMapper){
            this.deptMapper = deptMapper;
        }
    
    
        @Test
        public void testGetById(){
            Dept dept = deptMapper.selectByPrimaryKey(10L);
            System.out.println(dept);
        }
    }