当前位置: 首页 > news >正文

JavaEE、Spring

 

目录

一、Spring系统架构

二、核心概念

 三、IoC入门案例

 四、DI入门案例

五、bean (使用XML配置bean)

1、基础配置

 2、bean别名配置

 3、bean作用范围

4、bean的实例化

1、通过构造器实例化bean

2、通过静态工厂实例化bean

3、通过实例工厂实例化bean

4、通过BeanFactory实例化bean(基于第三种方式改良)(重要!)

5、bean的生命周期

 六、依赖注入

1、依赖注入的方式

1、setter注入

使用setter注入基本类型

使用setter注入引用类型

2、构造器注入

使用构造器注入引用类型

 使用构造器注入基本类型

2、依赖注入的方式选择

3、依赖自动装配

1、使用类型(byType)自动装配

2、使用名称(byName)自动装配

 4、集合注入

5、管理数据源对象

6、Spring加载properties文件

 七、容器

1、创建容器

2、获取bean

3、ApplicationContext实现类

八、核心容器、bean与依赖注入总结

九、注解开发

1、注解开发定义bean

 2、纯注解开发

  3、注解中bean的管理

1、bean的作用范围

 2、bean的生命周期

4、使用注解依赖注入

1、自动装配

         2、注解加载外部文件

 5、注解中第三方bean的管理

6、对外部bean依赖注入

1、注入简单类型

 2、注入引用类型

 7、注解开发总结

十、Sping整合其他框架

1、Spring整合MyBatis

2、Sping整合Junit

十一、AOP

1、AOP入门案例

2、AOP工作流程

3、AOP切入点表达式

1、切入点表达式规则

2、切入点表达式通配符

3、书写技巧

4、AOP通知类型(切面注解)

5、AOP通知获取数据

6、AOP案例:百度网盘分享链接输入密码AOP处理

7、AOP总结

 十二、Spring事务

 Spring事务角色


一、Spring系统架构

二、核心概念

当前书写代码存在的问题:业务层中要使用Dao层的实现类就需要new一个实现类对象,如果这时又来一个实现类对象就要修改业务层代码,有需要重新编译测试,代码耦合度极高

 使用IoC控制反转将对象的创建权交给外部,不要再new一个对象

 

 三、IoC入门案例

<!--1、导入spring坐标-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.16</version>
    </dependency>
<!--1、导入依赖坐标-->
    <!--2、创建Bean 存放实现类对象的全限定名-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" />

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        
    </bean>
public class BookServiceImpl implements BookService {
   
    private BookDao bookDao = new BookDaoImpl();

    @Override
    public void save() {
        System.out.println("bookservice");
        bookDao.save();
    }

}

 四、DI入门案例

由于在service中仍然new了dao的对象才能调用dao方法,没有实现真正解耦

<!--1、导入依赖坐标-->
    <!--2、创建Bean 存放实现类对象的全限定名-->
    <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" />

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <!--3、关系绑定,依赖注入-->
        <!--service中需要创建dao的对象,所以绑定在service-->
        <!--
            property配置当前bean的属性
            name 表示service层定义的对象名  private BookDao bookDao;
            ref 表示service层定义的对象名对应的bean对象名 id值
        -->
        <property name="bookDao" ref="bookDao"></property>
    </bean>
public class BookServiceImpl implements BookService {
    //仍然new了实现类对象才能进行数据交互
    //private BookDao bookDao = new BookDaoImpl();

    //1、删除new的实现类对象
    private BookDao bookDao;

    @Override
    public void save() {
        System.out.println("bookservice");
        bookDao.save();
    }

    //2、创建setBookDao方法
    public void setBookDao(BookDao bookDao){
        this.bookDao = bookDao;
    }

}

五、bean (使用XML配置bean)

1、基础配置

 2、bean别名配置

 3、bean作用范围

可以看到虽然表面创建了两个不同的Dao对象,但他们都指向同一个bean ,所以bean的作用范围默认为单例,因为如果是非单例,每使用一次这个bean都会再重新创建一次这个bean会使得容器中的bean越来越多

 可以通过scope属性设置非单例

<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>

4、bean的实例化

1、通过构造器实例化bean

public class BookDaoImpl implements BookDao {

    public BookDaoImpl() {
        System.out.println("bookdaoimpl构造器被调用");
    }

    @Override
    public void save() {
        System.out.println("bookdao");
    }
}

可以看到Spring对bean进行实例化会默认通过无参构造器创建bean对象,通过反射实现

2、通过静态工厂实例化bean

public class BookDaoFactory {
    //创建一个BookDao 工厂,提供创建BookDaoImpl的方法
    public static BookDao getBookDao(){
        System.out.println("factory start");
        return new BookDaoImpl();
    }
}
    <!--方式二:使用静态工厂实例化bean
    提供工厂路径,注明调用工厂的哪一个方法-->
    <bean id="bookDao" class="com.itheima.factory.BookDaoFactory" factory-method="getBookDao"></bean>

3、通过实例工厂实例化bean

public class BookDaoFactory2 {
    //创建实例工厂
    public BookDao getBookDao(){
        System.out.println("实例工厂被调用");
        return new BookDaoImpl();
    }
}
<!--方式三:使用实例工厂实例化bean
    先创建工厂的bean对象-->
    <bean id="BookFactory" class="com.itheima.factory.BookDaoFactory2"></bean>
    <!--再通过工厂创建具体的bean-->
    <bean id="bookDao" factory-method="getBookDao" factory-bean="BookFactory"></bean>

4、通过BeanFactory实例化bean(基于第三种方式改良)(重要!)

//实现FactoryBean接口,声明泛型类型,可能还有其他的bean需要实例化只需要修改泛型类型即可
public class BookFactoryBean implements FactoryBean<BookDao> {

    @Override
    public BookDao getObject() throws Exception {
        System.out.println("factorybean 启动");
        //返回BookDao的实现类
        return new BookDaoImpl();
    }

    @Override
    public Class<?> getObjectType() {
        //声明返回对象的类型
        return BookDao.class;
    }

    @Override
    public boolean isSingleton() {
        //此处为true说明实例化的对象为单例(同一个bean),false为非单例
        return true;
    }
}
<!--方式四-->
<!--实际上是factory工厂通过方法创造的bean对象-->
<bean id="bookDao" class="com.itheima.factory.BookFactoryBean"></bean>

5、bean的生命周期

 六、依赖注入

1、依赖注入的方式

1、setter注入

上节bean的实例化都是使用setter注入的方式进行

  • 使用setter注入基本类型

public class BookServiceImpl2 implements BookService {
    //使用setter注入 注入基本类型
    private int maxLink;
    private String databaseName;

    public void setMaxLink(int maxLink) {
        this.maxLink = maxLink;
    }

    public void setDatabaseName(String databaseName) {
        this.databaseName = databaseName;
    }

    public void save() {
        System.out.println("bookservice被创建");
        System.out.println(maxLink +"..."+ databaseName);
    }
}
<bean id="bookService2" class="com.itheima.service.impl.BookServiceImpl2">
        <!--使用value设置基本类型的值-->
        <property name="maxLink" value="10"/>
        <property name="databaseName" value="uesr"/>
    </bean>

  • 使用setter注入引用类型

public class BookServiceImpl implements BookService {
    private BookDao bookDao;
    private UserDao userDao;

    
    //创建set方法
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

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

    public void save() {
        System.out.println("bookservice被创建");
        bookDao.save();
        userDao.save();
    }
}
<!--<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>-->
    <bean id="bookdao" class="com.itheima.dao.impl.BookDaoImpl"></bean>

    <bean id="userdao" class="com.itheima.dao.impl.UserDaoImpl"></bean>

    <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl">
        <!--设置setter注入-->
        <property name="bookDao" ref="bookdao"></property>
        <property name="userDao" ref="userdao"></property>
    </bean>

2、构造器注入

  • 使用构造器注入引用类型

public class BookServiceImpl3 implements BookService {
    //使用setter注入 注入基本类型
    private BookDao bookDao1;
    private UserDao userDao1;

    //使用构造器注入,设置构造器参数
    public BookServiceImpl3(BookDao bookDao1,UserDao userDao1) {
        this.bookDao1 = bookDao1;
        this.userDao1 = userDao1;
    }

    public void save() {
        System.out.println("bookservice被创建");
        bookDao1.save();
        userDao1.save();
    }
}
  <bean id="bookService3" class="com.itheima.service.impl.BookServiceImpl3">
        <!--name中是形参的名称 ref是对应bean的id-->
        <constructor-arg name="bookDao1" ref="bookdao"/>
        <constructor-arg name="userDao1" ref="userdao"/>
    </bean>

  •  使用构造器注入基本类型

仅仅修改配置文件中的ref  化成value

但是当前构造器注入仍然存在紧耦合的问题,参数名一旦发生改变配置文件就要相对应的改变

所以Spring给出了解决方案

 <bean id="bookService3" class="com.itheima.service.impl.BookServiceImpl3">
        <!--不使用名称name绑定,而是使用参数的类型进行绑定-->
        <constructor-arg type="com.itheima.dao.BookDao" ref="bookdao"/>
        <constructor-arg type="com.itheima.dao.UserDao" ref="userdao"/>
    </bean>

但是使用这种方式也可能会出现参数类型相同的情况所以又引出了第二种解决方案

<bean id="bookService3" class="com.itheima.service.impl.BookServiceImpl3">
        <!--使用index索引根据参数位置匹配,解决了参数类型重复问题-->
        <constructor-arg index="0" ref="bookdao"/>
        <constructor-arg index="1" ref="userdao"/>
    </bean>

2、依赖注入的方式选择

构造器注入是必须注入的,而setter注入是可选的可注可不注

3、依赖自动装配

1、使用类型(byType)自动装配

2、使用名称(byName)自动装配

<!--使用自动装配-->
    <!--通过名称自动装配 这里要使入口的set方法名称与对应bean的id相同
        例如setBookDao 去set小写,bookDao,这个名称要与bookDao的bean的id相同
    -->
    <bean id="bookService4" class="com.itheima.service.impl.BookServiceImpl4" autowire="byName"/>
public class BookServiceImpl4 implements BookService {
    //使用setter注入 注入基本类型
    private BookDao bookDao;
    private UserDao userDao;

    //使用setter方法设置自动装配入口
    public void setBookDao(BookDao bookDao) {
        this.bookDao = bookDao;
    }

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

    public void save() {
        System.out.println("bookservice被创建");
        bookDao.save();
        userDao.save();
    }
}

 

 4、集合注入

 

 如果集合中要加入引用类型的数据将value改为ref

5、管理数据源对象

用IoC容器来管理外部导入的资源,例如druid数据库连接池,junit测试等依赖

 <!--配置外部数据源-->
    <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
        <!--需要配置的属性-->
        <property name="driverClassName" value="com.mysql.jdbc.Driver"/>
        <property name="url" value="jdbc:mysql://localhost:3306"/>
        <property name="username" value="123"/>
        <property name="password" value="123"/>
    </bean>

6、Spring加载properties文件


<!--1、开启一个全新的命名空间-->
<beans xmlns="http://www.springframework.org/schema/beans"
       xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"

       xmlns:context="http://www.springframework.org/schema/context"

       xsi:schemaLocation="http://www.springframework.org/schema/beans
                           http://www.springframework.org/schema/beans/spring-beans.xsd
                           http://www.springframework.org/schema/context
                           http://www.springframework.org/schema/context/spring-context.xsd">

    <!--2、使用新的命名空间引入properties文件-->
    <!--system-properties-mode="NEVER"从不加载系统属性,防止文件名称与系统名称冲突-->
    <context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/>

    <!--3、使用占位符获取文件中的数据-->
    <bean class="com.alibaba.druid.pool.DruidDataSource">
        <property name="driverClassName" value="${jdbc.driverClassName}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
    </bean>


</beans>

 

 七、容器

1、创建容器

//1、使用类路径创建容器
        ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
        //2、使用文件系统绝对路径创建容器
        ApplicationContext ctx = new FileSystemXmlApplicationContext("D:\\2ProgramTool\\JavaEETest\\stage1\\springdemo3\\src\\main\\resources\\jdbc.properties");
        

2、获取bean

3、ApplicationContext实现类

ApplicationContext的祖宗接口就是BeanFactory

八、核心容器、bean与依赖注入总结

 

 

九、注解开发

1、注解开发定义bean

 2、纯注解开发

 使用纯注解定义bean


//1、创建配置类代替配置文件
@Configuration //代表配置文件
@ComponentScan("com.itheima") //代表包扫描组件
@ComponentScan({"com.itheima","com.ittest"}) //在多个包扫描组件
public class SpringConfig {
    //使用配置类代替配置文件
}
//2、定义bean
@Repository("bookDao")
public class BookDaoImpl implements BookDao {

    public void save() {
        System.out.println("注解开发");
    }
}
//3、使用bean
public class App {
    public static void main(String[] args) {

        //使用纯注解开发将不再需要applicatinContext文件
        ApplicationContext ctx = new AnnotationConfigApplicationContext(SpringConfig.class);
        //通过组件名称
        BookDao bookDao = ctx.getBean("bookDao", BookDao.class);
        System.out.println(bookDao);
    }
}

3、注解中bean的管理

1、bean的作用范围

 2、bean的生命周期

4、使用注解依赖注入

1、自动装配

注入引用类型

@Repository("bookDao")
public class BookDaoImpl implements BookDao {

    @Autowired  //默认按类型自动装配,不需要写setter入口
    @Qualifier("mappDao") //按名称装配
    private Mapp mapp;

    public void save() {
        System.out.println("bookDao被创建");
        mapp.save();
    }
}

 注入基本类型

 2、注解加载外部文件

 5、注解中第三方bean的管理

@Configuration //代表配置文件
@ComponentScan("com.itheima") //代表扫描组件
@PropertySource({"jdbc.properties","jdbc2.properties","jdbc3.properties","jdbc2-1.properties"})
public class SpringConfig {
    //使用配置类代替配置文件
    
    @Bean  //说明返回类型是一个bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
        ds.setName("root");
        ds.setPassword("root");
        return ds;
    }
}

在实际开发中,外部的bean一般另外创建一个类来创建bean,然后导入的方式加到配置文件中

//1、单独创建一个类
public class JdbcConfig {
    @Bean  //说明返回类型是一个bean
    public DataSource dataSource(){
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName("com.mysql.jdbc.Driver");
        ds.setUrl("jdbc:mysql://localhost:3306/spring_db");
        ds.setName("root");
        ds.setPassword("root");
        return ds;
    }
}
@Configuration //代表配置文件
@Import(JdbcConfig.class) //导入外部bean 多个外部bean使用数组形式
public class SpringConfig {
    //使用配置类代替配置文件

}

6、对外部bean依赖注入

1、注入简单类型

 2、注入引用类型

直接设置参数,会进行自动装配

 7、注解开发总结

十、Sping整合其他框架

1、Spring整合MyBatis

导入坐标

  <!--spring整合mybatis需要使用的坐标-->
  <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-jdbc</artifactId>
    <version>5.3.16</version>
  </dependency>
  <dependency>
    <groupId>org.mybatis</groupId>
    <artifactId>mybatis-spring</artifactId>
    <version>1.3.0</version>
  </dependency>

 创建jdbc.properties外部文件

driver=com.mysql.jdbc.Driver
url=jdbc:mysql://localhost:3306/users?useSSL=false
username=root
password=12345

设置数据源 jdbc连接数据库

public class JdbcConfig {
    @Value("${driver}")
    private String driverClassName;
    @Value("${url}")
    private String url;
    @Value("${name}")
    private String name;
    @Value("${password}")
    private String password;

    @Bean
    public DataSource dataSource(){
        //创建jdbc的数据库连接池DataSource
        DruidDataSource ds = new DruidDataSource();
        ds.setDriverClassName(driverClassName);
        ds.setUrl(url);
        ds.setName(name);
        ds.setPassword(password);
        return ds;
    }
}

配置类

@Configuration
@ComponentScan("com.itheima")
@PropertySource("jdbc.properties")
@Import({JdbcConfig.class,MyBatisConfig.class})
public class SpringConfig {
}

2、Sping整合Junit

 导入坐标

<!--spring整合junit-->
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-test</artifactId>
      <version>5.3.16</version>
    </dependency>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.12</version>
      <scope>test</scope>
    </dependency>

 使用专用类运行器RunWith

@RunWith(SpringJUnit4ClassRunner.class)
//与配置类接通
@ContextConfiguration(classes = SpringConfig.class)
public class ServiceTest {

    @Autowired
    private AccountService accountService;

    @Test
    public void testSelectById(){
        System.out.println(accountService.selectById(2));
    }
}

十一、AOP

1、AOP入门案例

 导入需要的坐标

在导入spring-context时是默认自动导入aop的坐标

  <dependencies>
    <dependency>
      <groupId>org.springframework</groupId>
      <artifactId>spring-context</artifactId>
      <version>5.3.16</version>
    </dependency>

    <dependency>
      <groupId>org.aspectj</groupId>
      <artifactId>aspectjweaver</artifactId>
      <version>1.9.4</version>
    </dependency>
  </dependencies>
//6、创建bean
@Component
//7、将这个bean作为AOP处理
@Aspect
public class MyAdvice {
    //2、创建通知类 定义通知方法

    //4、定义切入点
    @Pointcut("execution(void com.itheima.dao.BookDao.update())")
    private void pt(){}
    
    //5、设置切入点的位置,作为切面绑定通知与切入点的关系
    @Before("pt()")
    public void advice(){
        //3、共性方法  通知
        System.out.println(System.currentTimeMillis());
    }

}
@Configuration
@ComponentScan("com.itheima")
//8、启动Aspect注解,开启AOP代理自动配置
@EnableAspectJAutoProxy
public class SpringConfig {
}

2、AOP工作流程

底层是代理模式增强功能

 

3、AOP切入点表达式

1、切入点表达式规则

 

2、切入点表达式通配符

 

3、书写技巧

 

4、AOP通知类型(切面注解)

 

    @Pointcut("execution(void com.itheima.dao.BookDao.update())")
    private void pt(){}
    @Pointcut("execution(int com.itheima.dao.BookDao.select())")
    private void pt2(){}

    //1、前置通知
//    @Before("pt()")
    public void advice(){
        System.out.println("before is running...");
    }

    //2、后置通知
//    @After("pt()")
    public void after(){
        System.out.println("after is running...");
    }
    //3、环绕通知
    @Around("pt2()")
    public Object around(ProceedingJoinPoint joinPoint) throws Throwable {
        System.out.println("before running...");
        //调用原始方法
        //Object proceed = joinPoint.proceed();
        //还要将原始方法的返回值返回出去
        Integer proceed = (Integer) joinPoint.proceed();

        System.out.println("after  running...");
        //还可以对原始方法的返回值进行修改
        return proceed;
    }

5、AOP通知获取数据

获取原始方法的参数数组,可以对参数进行修改,注意如果使用了JoinPoint作为参数一定要放在参数最前面。

 6、AOP案例:百度网盘分享链接输入密码AOP处理

 

@Component
@Aspect
public class BaiduAop {

    @Pointcut("execution(boolean com.itheima.service.*Service.judgement(*,*))")
    public void pt(){}


    @Around("BaiduAop.pt()")
    public Object trimStr(ProceedingJoinPoint pjp) throws Throwable {

        //获取参数数据
        Object[] args = pjp.getArgs();
        //对参数数组遍历,对字符串类型的参数进行trim处理
        for (int i = 0; i < args.length; i++) {
            if (args[i].getClass().equals(String.class)){
                //如果是字符串就处理并修改参数
                args[i] = args[i].toString().trim();
            }
        }
        //将修改后的参数再传递给原始函数
        Object proceed = pjp.proceed(args);
        return proceed;

    }
}

7、AOP总结

 

 十二、Spring事务

 

 

 

 

 Spring事务角色

 

相关文章:

  • setTimeout和setInterval区别,以及定时器的传参功能
  • 【数学分析笔记04】数列与数列极限
  • 1、设计模式的简介
  • .NET LINQ 通常分 Syntax Query 和Syntax Method
  • deepstream--nvinfer
  • python+vue+elementui企业会议管理系统django
  • centos 部署java环境,拷贝jar包并运行
  • 支持在线写SQL的Oracle学习免费网站(个人常使用)
  • ESP8266-Arduino编程实例-SHT20温湿度传感器驱动
  • 【web-代码审计】(14.5)PHP
  • Waline评论服务docker自部署手册 + 无需备案域名配置
  • [202209]mysql8.0 双主集群搭建 亲测可用
  • C++后台开发学习路线(已多人拿下腾讯后台开发)
  • 中值滤波器 median filter
  • 基于ssm的图书(借阅)管理系统
  • (三)从jvm层面了解线程的启动和停止
  • [译] 理解数组在 PHP 内部的实现(给PHP开发者的PHP源码-第四部分)
  • [译] 怎样写一个基础的编译器
  • laravel5.5 视图共享数据
  • miniui datagrid 的客户端分页解决方案 - CS结合
  • MYSQL 的 IF 函数
  • nginx 配置多 域名 + 多 https
  • node入门
  • PHP的Ev教程三(Periodic watcher)
  • 翻译:Hystrix - How To Use
  • 回顾2016
  • 机器学习 vs. 深度学习
  • 基于web的全景—— Pannellum小试
  • 跨域
  • 模仿 Go Sort 排序接口实现的自定义排序
  • 腾讯优测优分享 | 你是否体验过Android手机插入耳机后仍外放的尴尬?
  • 想写好前端,先练好内功
  • 运行时添加log4j2的appender
  • 曜石科技宣布获得千万级天使轮投资,全方面布局电竞产业链 ...
  • ​linux启动进程的方式
  • ​人工智能书单(数学基础篇)
  • # Swust 12th acm 邀请赛# [ A ] A+B problem [题解]
  • #HarmonyOS:基础语法
  • (10)ATF MMU转换表
  • (145)光线追踪距离场柔和阴影
  • (zt)最盛行的警世狂言(爆笑)
  • (翻译)terry crowley: 写给程序员
  • (附源码)springboot优课在线教学系统 毕业设计 081251
  • (离散数学)逻辑连接词
  • (免费领源码)Java#Springboot#mysql农产品销售管理系统47627-计算机毕业设计项目选题推荐
  • (转)程序员疫苗:代码注入
  • (转)详解PHP处理密码的几种方式
  • .[backups@airmail.cc].faust勒索病毒的最新威胁:如何恢复您的数据?
  • .NET CORE 2.0发布后没有 VIEWS视图页面文件
  • .net6解除文件上传限制。Multipart body length limit 16384 exceeded
  • @CacheInvalidate(name = “xxx“, key = “#results.![a+b]“,multi = true)是什么意思
  • []error LNK2001: unresolved external symbol _m
  • [2019.3.5]BZOJ1934 [Shoi2007]Vote 善意的投票
  • [C/C++]数据结构----顺序表的实现(增删查改)
  • [hdu 1247]Hat’s Words [Trie 图]