Spring


Spring

MVC设计模式:当拿到任何一个需求的时候,都可以从MVC三个方面进行拆分

  • M:Model,模型,处理数据

  • V:View,视图,接收和显示数据

  • C:Controller,控制器,由谁来接收和显示数据,有谁来处理数据

三层结构:企业级应用的要求

  • 表示层
  • 业务逻辑层
  • 数据访问层

概述

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

使用

  1. 添加 spring 依赖

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

    @Configuration
    public class AppConfig {
        
        @Bean(name = {"empDao1","empDao2"})
        public EmpDao empDao() {
            return new EmpDaoImpl();
        }
    }
    
  3. 测试

    public class EmpDaoTest {
        
        @Test
        public void testInsert() {
            //启动容器
            ApplicationContext c =
                    new AnnotationConfigApplicationContext(AppConfig.class);
            //得到组件
            //EmpDao empDao = c.getBean(EmpDao.class);
            //通过组件名得到组件,默认是方法名
            EmpDao empDao = (EmpDao)c.getBean("empDao2");
            //调用业务方法
            empDao.insert();
            //关闭容器
            ((AnnotationConfigApplicationContext)c).close();
        }
    
    }
    
  4. 组件装配

    @Getter
    @Setter
    public class EmpServiceImpl implements EmpService {
    
        private EmpDao empDao ;
        @Override
        public int insert() {
            
            return empDao.insert();
        }
    
    }
    

    属性注入:

    @Configuration
    public class AppConfig {
        
        @Bean(name = {"empDao1","empDao2"})
        public EmpDao empDao() {
            return new EmpDaoImpl();
        }
        
        @Bean
        public EmpService empService() {
            EmpServiceImpl service = new EmpServiceImpl();
            //依赖注入
            service.setEmpDao(empDao());
            
            return service;
        }
    }
    

    构造注入:

    @Getter
    @Setter
    public class EmpServiceImpl implements EmpService {
        public EmpServiceImpl() {
            
        }
        
        public EmpServiceImpl(EmpDao empDao) {
            this.empDao = empDao;
        }
    
        private EmpDao empDao ;
        @Override
        public int insert() {
            
            return empDao.insert();
        }
    
    }
    
    @Bean
        public EmpService empService() {
            EmpServiceImpl service = new EmpServiceImpl(empDao());
                    
            return service;
        }
    

    依赖注入三种方式:

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

Bean说明

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

    @Bean
    @Scope("prototype")
    public EmpService empService() {
        EmpServiceImpl service = new EmpServiceImpl(empDao());
    
        return service;
    }
    
  2. @Lazy:懒加载(延迟加载,在getBean()的时候再加载),默认值@Lazy(false)

    注意:在@Scope(“prototype”)的时候,一定是懒加载的

        @Bean
    //	@Scope("prototype")
        @Lazy(true)
        public EmpService empService() {
            EmpServiceImpl service = new EmpServiceImpl(empDao());
            
            return service;
        }
    
  3. 组件扫描

    • 在配置类上添加组件扫描注解

      @Configuration
      @ComponentScan(basePackages = {"com.neu.dao","com.neu.service"})
      public class AppConfig {}
      
    • 在需要成为组件的类上添加@Component注解(组件默认名字为:类名首字母小写)

      //组件
      @Component
      public class EmpDaoImpl implements EmpDao {}
      
  4. 自动装配

    //默认按照类型装配
    @Autowired
    private EmpDao empDao ;
    
  5. 解决自动装配冲突(使用组件名装配)

    @Autowired
    @Qualifier("empOracleDaoImpl")//注解参数就是组件名,默认为类名首字母小写
    private EmpDao empDao ;
    
  6. 修改组件的默认名

    @Component(value = "oracleemp")
    public class EmpOracleDaoImpl implements EmpDao {}
    

使用Spring的测试模块

  1. 导入依赖

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-test</artifactId>
        <version>4.3.8.RELEASE</version>
    </dependency>
    
  2. 测试

    //设置配置文件
    @ContextConfiguration(classes = {AppConfig.class})
    //相当于测试框架与Spring的一个接口
    @RunWith(SpringJUnit4ClassRunner.class)
    public class EmpTest {
        @Autowired
        private EmpService empService;
        
        @Test
        public void testInsert() {
            empService.insert();
        }
    
    }
    

Spring对持久层的支持

在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. 定义一个配置类,读取数据库连接属性文件

    package com.neu;
    
    import javax.sql.DataSource;
    
    import org.apache.commons.dbcp.BasicDataSource;
    import org.springframework.beans.factory.annotation.Value;
    import org.springframework.context.annotation.Bean;
    import org.springframework.context.annotation.Configuration;
    import org.springframework.context.annotation.PropertySource;
    
    @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 int maxActive;
        
        @Value("${jdbc.maxWait}")
        private int maxWait;
        
        @Value("${jdbc.maxIdle}")
        private int maxIdle;
        
        @Bean
        public DataSource dataSource() {
            BasicDataSource ds = new BasicDataSource();
            ds.setUsername(username);
            ds.setPassword(password);
            ds.setUrl(url);
            ds.setDriverClassName(driverClassName);
            
            ds.setMaxActive(maxActive);
            ds.setMaxIdle(maxIdle);
            ds.setMaxWait(maxWait);
            
            return ds;
        }
    }
    
  4. 测试

    @ContextConfiguration(classes = {AppConfig.class,DBConfig.class})
    //相当于测试框架与Spring的一个接口
    @RunWith(SpringJUnit4ClassRunner.class)
    public class EmpTest {
        @Autowired
        private EmpService empService;
        
        @Autowired
        private DataSource dataSource;
        
        @Test
        public void testDataSource() throws SQLException {
            Connection connection = dataSource.getConnection();
            System.out.println("连接成功!");
            connection.close();
        }
        
        @Test
        public void testInsert() {
            empService.insert();
        }
    
    }
    

    Spring与Mybatis集成

    1. 导入依赖

      <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
      @ComponentScan(basePackages = {"com.neu.service","com.neu.mapper"})
      public class MybatisConfig {
          @Autowired
          private DataSource dataSource;
          
          @Bean
          public SqlSessionFactory sqlSessionFactory() throws Exception {
              SqlSessionFactoryBean factory = new SqlSessionFactoryBean();
              factory.setDataSource(dataSource);
              
              return factory.getObject();
          }
      }
      
    3. 配置 mapper 扫描

      @Configuration
      public class MybatisMapperScannerConfig {
      
          @Bean
          public MapperScannerConfigurer mapperScannerConfigurer() {
              MapperScannerConfigurer c = new MapperScannerConfigurer();
              c.setSqlSessionFactoryBeanName("sqlSessionFactory");
              
              c.setBasePackage("com.neu.mapper");
              
              return c;
          }
      }
      

作业

  1. spring+mybatis实现如下功能(使用单元测试,业务逻辑层+数据访问层):
    • 查询所有员工信息
    • 添加员工
    • 删除员工
    • 分页查询员工(每页显示3条记录,打印第2页数据)

Spring+Mybatis+Servlet

  1. 修改打包方式:war

  2. 导入相关web依赖

    <dependency>
        <groupId>org.springframework</groupId>
        <artifactId>spring-web</artifactId>
        <version>4.3.8.RELEASE</version>
    </dependency>
    

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. 定义一个类,实现切面的功能(类定义在com.neu.utils包下,要把该包添加到组件的扫描路径中)

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

    @Before("pointcut()")
        public void before() {
            SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String format = f.format(new Date());
            
            System.out.println("开始执行方法:"+format);
            
        }
    
  5. 返回后通知:执行了return语句后执行的代码

    @AfterReturning("pointcut()")
        public void afterReturning() {
            SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String format = f.format(new Date());
            
            System.out.println("方法正常结束:"+format);
            
        }
    
  6. 异常通知:

    @AfterThrowing("pointcut()")
        public void afterThrowing() {
            SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String format = f.format(new Date());
            
            System.out.println("抛出异常:"+format);
            
        }
    
  7. 最终通知

    @After("pointcut()")
        public void after() {
            SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            String format = f.format(new Date());
            
            System.out.println("方法最终结束时间:"+format);
            
        }
    
  8. 环绕通知

    @Around("pointcut()")
        public Object around(ProceedingJoinPoint p) throws Throwable {
            long startTime = System.nanoTime();
            //调用代理的方法
            Object object = p.proceed();
            
            long m = System.nanoTime() - startTime;
            
            System.out.println(m);
            
            return object;
        }
    

Spring对事务的支持

  1. 添加事务管理器

    @Bean
    public PlatformTransactionManager transactionManager() {
        return new DataSourceTransactionManager(dataSource());
    }
    
  2. 启用事务管理器

    @Configuration
    //配置属性源文件
    @PropertySource("classpath:db.properties")
    @EnableTransactionManagement//启用事务管理器
    public class DBConfig {}
    
  3. 在业务逻辑类上或方法上添加@Transactional

    当添加了事务注解的方法中,抛出异常,则回滚事务,否则,提交事务

    @Transactional
        public int insert(Dept dept) {
            deptMapper.insert(dept);
            return deptMapper.insert(dept);
        }
    

使用静态资源

  1. 在 webapp 目录下,新建一个文件夹:staitc,在其中放入静态资源(css、js)

    例如:/webapp/static/css/style1.css

  2. 配置资源注册

    @Configuration
    @EnableWebMvc//启用mvc注解驱动
    @ComponentScan(basePackages = "com.neu.controller")
    public class SpringMVCConfig implements WebMvcConfigurer {
        @Override
        public void addResourceHandlers(ResourceHandlerRegistry registry) {
            registry.addResourceHandler("/static/**").addResourceLocations("/static/");//访问的静态资源
        }
    }
    
  3. 在 jsp 中引入css

    <link rel="stylesheet" href="${ pageContext.request.contextPath }/static/css/style1.css">
    

文章作者: FFFfrance
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 FFFfrance !