Spring框架
Spring就是一个能够简化开发和框架整合的技术。
一、IOC控制反转
概念:对象创建权由程序转移到外部,这种思想被称为控制反转。
spring技术对ioc思想进行了实现:spring提供了一个容器,称为ioc容器,用来充当ioc思想中的“外部”。
ioc容器负责对象的创建、初始化等一系列工作,被创建或被管理的对象在ioc容器中统称为bean。
在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入DI。
二、spring的入门案例
1.pom文件中导入坐标
<dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency>
2.定义spring管理的类
3,在配置文件中配置bean路径
<bean id="BookDao" class="com.itheima.dao.impl.BookDaoImpl"></bean> <bean id="BookService" class="com.itheima.service.impl.BookServiceImpl"></bean>
4.在主方法中调用,通过创建容器、加入配置文件、获取bean的方式
//将配置加入到容器中 ApplicationContext ctx=new ClassPathXmlApplicationContext ("ApplicationContext.xml"); //获取bean // BookDao bookDao = (BookDao) ctx.getBean ("BookDao"); // bookDao.save (); BookService bookService = (BookService) ctx.getBean ("BookService"); bookService.save (); }
三、DI依赖注入的入门案例
1.spring管理的类中,删除通过new方式创建的dao对象,创建通过set方法bean入口
//5.删除业务层中使用new的方式创建的dao对象 private BookDao bookDao; public void save() { System.out.println ("book service save ..."); bookDao.save (); } //6.set方法,给容器一个入口 public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } }
2.在配置文件中配置(要有当前bean的属性名和当前id名)
<bean id="BookService" class="com.itheima.service.impl.BookServiceImpl"> <!--property是当前bean的属性,name是属性名,ref是当前id名--> <property name="bookDao" ref="BookDao"></property> </bean>
四、Bean的作用范围
可以在配置文件中通过scope设置单例和非单例
<bean id="bookDao" name="dao" class="com.itheima.dao.impl.BookDaoImpl" scope="prototype"/>
为什么bean会默认是单例?
如果bean不是单例,那么需要一个bean就创建一个,对容器会造成很大的压力,而容器负责管理的的是那些可以复用的bean。
五、实例化bean的三种方式
第一种:构造方法
1.在实现类中创建空参构造方法
public class BookDaoImpl implements BookDao { public BookDaoImpl() { System.out.println("book dao constructor is running ...."); }
public void save() { System.out.println("book dao save ..."); } }
2.配置文件中配置
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/>
第二种:静态工厂实例化bean
和第一种不同的是,需要创建一个静态工厂类,并且要在这个类中创建对象,返回给实现类
1.静态工厂与实现类
//静态工厂创建对象 public class OrderDaoFactory { public static OrderDao getOrderDao(){ System.out.println("factory setup...."); return new OrderDaoImpl(); } } public class OrderDaoImpl implements OrderDao { public void save() { System.out.println("order dao save ..."); } }
2.配置文件,需要配置工厂方法,工厂路径
<bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/>
第三种:使用实例化工厂
和第二种不同的就是一个是静态,一个普通方法
//实例工厂创建对象 public class UserDaoFactory { public UserDao getUserDao(){ return new UserDaoImpl(); } }
配置文件(需要创建两个bean,一个是工厂的bean,一个是实现类的bean,实现类的bean需要添加工厂方法和工厂bean)
<bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/> <bean id="userDao" factory-method="getUserDao" factory-bean="userFactory"/>
第三种变式:使用FactoryBean
由于第三种的配置文件编写的可扩展性低,因此可以使用这个变式
1.在实现类中实现FactoryBean这个方法
//FactoryBean创建对象 public class UserDaoFactoryBean implements FactoryBean<UserDao> { //代替原始实例工厂中创建对象的方法 public UserDao getObject() throws Exception { return new UserDaoImpl(); } public Class<?> getObjectType() { return UserDao.class; } }
2.在配置文件中正常编写bean
<bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>
六、bean生命周期
初始化容器
1.创建对象(内存分配)
2.执行构造方法
3.执行属性注入(Set操作)
4.执行bean初始化方法
使用bean
<bean id="BookService" class="com.itheima.service.impl.BookServiceImpl"> <!--property是当前bean的属性,name是属性名,ref是当前id名--> <property name="bookDao" ref="BookDao"></property> <property name="userDao" ref="UserDao"></property> </bean>
简单类型注入
在业务层中进行变量的定义和set方法进入容器,然后在配置文件中通过property标签给指定变量赋值
<bean id="BookDao" class="com.itheima.dao.impl.BookDaoImpl"> <property name="number" value="100"></property> <property name="season" value="mysql"></property> </bean>
八、构造器注入(相当于setter注入换个壳)
1.引用注入:在业务层实现类中通过实现构造方法,进入容器,然后在配置文件中通过constructor-arg标签指定的bean
<bean id="UserDao" class="com.itheima.dao.impl.UserDaoImpl"></bean> <bean id="BookService" class="com.itheima.service.impl.BookServiceImpl"> <constructor-arg name="bookDao" ref="BookDao"></constructor-arg> <constructor-arg name="userDao" ref="UserDao"></constructor-arg> </bean>
2.简单注入:通过在业务层实现类中定义变量,然后通过构造器注入进入容器,通过constructor-arg给赋值,但是可以按类型,按名字,按索引进行赋值
<bean id="BookDao" class="com.itheima.dao.impl.BookDaoImpl"> <constructor-arg index="0" value="10"></constructor-arg> <constructor-arg index="1" value="mysqwl"></constructor-arg> </bean>
九、依赖自动装配
需要用到setter注入,在xml上不用配置其他
<!--依赖自动装配--> <bean id="BookDao" class="com.itheima.dao.impl.BookDaoImpl"/> <bean id="UserDao" class="com.itheima.dao.impl.UserDaoImpl"></bean> <bean id="BookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/>
特征:
1.自动装配用于引用类型依赖注入,不能对简单类型进行操作
2、使用byType时,必须保证容器中相同类型的bean是唯一的
3.使用byName时,必须保证容器中具有指定名称的bean
4.自动装配优先级低于setter注入与构造器注入 ,同时出现,自动装配配置失效
十、集合注入
public class BookDaoImpl implements BookDao { private int[] array; private List<String> list; private Set<String> set; private Map<String,String> map; private Properties properties; public void setArray(int[] array) { this.array = array; } public void setList(List<String> list) { this.list = list; } public void setSet(Set<String> set) { this.set = set; } public void setMap(Map<String, String> map) { this.map = map; } public void setProperties(Properties properties) { this.properties = properties; } public void save() { System.out.println("book dao save ..."); System.out.println("遍历数组:" + Arrays.toString(array)); System.out.println("遍历List" + list); System.out.println("遍历Set" + set); System.out.println("遍历Map" + map); System.out.println("遍历Properties" + properties); } }
配置文件
<bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> <property name="array"> <array> <value>1</value> <value>2</value> <value>3</value> </array> </property> <property name="list"> <list> <value>1</value> <value>12</value> <value>13</value> </list> </property> <property name="map"> <map> <entry key="1" value="221"></entry> <entry key="2" value="22"></entry> <entry key="3" value="34"></entry> </map> </property> <property name="set"> <set> <value>1</value> <value>12</value> <value>13</value> </set> </property> <property name="properties"> <props> <prop key="1">2</prop> <prop key="12">23</prop> <prop key="13">23</prop> </props> </property> </bean>
容器内容相关总结
1.BeanFactory是IoC容器的顶层接口,初始化BeanFactory对象时,加载的bean延迟加载
2.ApplicationContext接口是Spring容器 的核心接口,初始化时bean立即加载
3.Application接口提供基础的bean操作相关方法,通过其他接口扩展其功能
十一、注解开发
1.把xml文件删除,新建一个SpringConfig配置类
@Configuration //代表xml文件中的那些配置网址那些
@ComponentScan("com.itheima") //代表扫描包语句
public class SpringConfig {
}
2.生成容器变成AnnotationConfigApplicationContext
public class App1 { public static void main(String[] args) { ApplicationContext ctx= new AnnotationConfigApplicationContext (SpringConfig.class); BookDao bookDao = (BookDao) ctx.getBean ("BookDao"); System.out.println (bookDao); BookService bookService = (BookService) ctx.getBean ("BookService"); System.out.println (bookService); }
十二、Bean的管理
@Scope("singleton")bean的作用范围
//初始化bean @PostConstruct
//销毁bean @PreDestroy
@Repository @Scope("singleton") //bean的作用范围,非单例 public class BookDaoImpl implements BookDao { public void save() { System.out.println ("sdsas...."); } //初始化bean @PostConstruct public void init() { System.out.println ("init...."); } //销毁bean @PreDestroy public void destroy() { System.out.println ("destory...."); } } public class App { public static void main(String[] args) { AnnotationConfigApplicationContext ctx=new AnnotationConfigApplicationContext (SpringConfig.class); BookDao bookDao = (BookDao) ctx.getBean (BookDao.class); BookDao bookDao1 = (BookDao) ctx.getBean (BookDao.class); System.out.println (bookDao); System.out.println (bookDao1); ctx.close (); //使用close之后才会执行销毁操作 } }
十三、
@Service public class BookServiceImpl implements BooklService { @Autowired //自动装配 @Qualifier("bookDao") //当出现两个一样的实现类时,进行指定的注解,要配合Auto一起使用,而且对应的类中一定添加名称,否则报错 private BookDao bookDao; public void run() { System.out.println ("boookService.."); bookDao.save (); } }
十四、第三方bean的管理
在JdbcConfig中配置好要管理的第三方内容
public class JdbcConfig { @Bean public DataSource dataSource(){ DruidDataSource ds=new DruidDataSource (); ds.setDriverClassName ("com.mysql.jdbc.Driver"); ds.setUrl ("jdbc:mysql//localhost:3306/spring_db"); ds.setUsername ("root"); ds.setPassword ("123456"); return ds; } }
在springconfig中导入配置
@Configuration @Import (JdbcConfig.class) @ComponentScan("com.study") public class SpringConfig { }
2.简单注入
public class JdbcConfig { @Value ("${com.mysql.jdbc.Driver}") private String DriverClassName; @Value ("${jdbc:mysql//localhost:3306/spring_db}") private String Url ; @Value ("${root}") private String Username; @Value ("${123456}") private String Password; @Bean public DataSource dataSource(BookDao bookDao){ System.out.println (bookDao); DruidDataSource ds=new DruidDataSource (); ds.setDriverClassName (DriverClassName); ds.setUrl (Url); ds.setUsername (Username); ds.setPassword (Password); return ds; } }
3.引用注入
在springConfig类中添加扫描
@ComponentScan("com.study")
在第三方bean中添加参数,让容器自动装配
@Bean public DataSource dataSource(BookDao bookDao){
<dependencies> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-context</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>com.alibaba</groupId> <artifactId>druid</artifactId> <version>1.1.16</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis</artifactId> <version>3.5.6</version> </dependency> <dependency> <groupId>mysql</groupId> <artifactId>mysql-connector-java</artifactId> <version>5.1.47</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-jdbc</artifactId> <version>5.2.10.RELEASE</version> </dependency> <dependency> <groupId>org.mybatis</groupId> <artifactId>mybatis-spring</artifactId> <version>1.3.0</version> </dependency>
2.使用SqlSessionBeanFactory进行相关资源的整合
mybaits中jdbc的连接映射资源以及对象属性包的扫描
//使用sqlsessionBeanFactory @Bean public SqlSessionFactoryBean sqlSeessionFactoryBean(DataSource dataSource){ SqlSessionFactoryBean ssfb=new SqlSessionFactoryBean (); ssfb.setTypeAliasesPackage ("com.itheima.domain"); ssfb.setDataSource (dataSource); return ssfb; }
3.使用MapperScannerConfigurer进行mapper映射基本包的扫描
@Bean public MapperScannerConfigurer mapperScannerConfigurer(){ MapperScannerConfigurer msc=new MapperScannerConfigurer (); msc.setBasePackage ("com.itheima.dao"); return msc; }
十六、Spring整合junit
1.导入坐标
要有junit和spring-test的坐标
<dependency> <groupId>junit</groupId> <artifactId>junit</artifactId> <version>4.3.1</version> </dependency> <dependency> <groupId>org.springframework</groupId> <artifactId>spring-test</artifactId> <version>5.3.10</version> </dependency>
2.创建一个测试类
@RunWith (SpringJUnitRunner.class) @ContextConfiguration(classes = SpringConfig.class) public class AccountServiceTest { @Autowired private AccountService accountService; @Bean public void testFindById(){ System.out.println (accountService.findById (1)); } }
十七、AOP
面向切面编程,一种编程范式,指导开发者如何组织程序结构
作用:在不惊动原始设计的基础上为其进行功能的增强
核心概念:
连接点:程序执行过程中的任意位置,粒度为执行方法、抛出异常、设置变量等。
通知:在切入点处执行的操作,也就是共性功能
通知类:定义通知的类
<dependency> <groupId>org.aspectj</groupId> <artifactId>aspectjweaver</artifactId> <version>1.9.4</version> </dependency>
2.制作连接点(dao接口与实现类)
@Repository public class BookDaoImpl implements BookDao { public void run() { System.out.println (System.currentTimeMillis ()); System.out.println ("book dao run...."); } public void update() { System.out.println ("book dao update....."); } }
3.制作共性功能(通知类与通知)
要在 通知类中添加注解@Aspect告诉容器这是一个通知类,然后创建一个空参构造方法加入注解切入点@Pointcut("execution(void com.study.dao.BookDao.update())") 启动到连接点的方法上,然后在创建一个共性方法,可以切入的方法
@Component @Aspect public class MyAdvice { @Pointcut("execution(void com.study.dao.BookDao.update())") //切入点:启动这个类下的方法 public void pt(){} @Before ("pt()") //在这个方法之前执行 public void method(){ System.out.println (System.currentTimeMillis ()); } }
4.在spring配置文件中编写注解@EnableAspectJAutoProxy
Aop工作流程
1.spring容器启动
2.读取所有切面配置中的切入点
3.初始化bean,判定bean对象的类中的方法是否匹配到任意切入点,否,创建对象,是,创建原始对象的代理对象
4.获取bean的执行方法
springAOP的本质:代理模式
核心概念:目标对象、代理
流程大概就是在执行容器后,系统自动扫描bean,如果有匹配aop的方法,那就有代理,否则就没有
切入点表达式
如何正确使用通配符
AOP的五中通知类型
@Pointcut("execution(* com.*.*.*.*())") public void pt(){} @Pointcut("execution(int com.study.dao.BookDao.select())") public void pt2(){} //前置通知 // @Before ("pt()") public void method(){ System.out.println (System.currentTimeMillis ()); } //后置通知 // @After ("pt()") public void method1(){ System.out.println ("afteradvice"); } //环绕通知 @Around ("pt2()") public Object Around(ProceedingJoinPoint pdj) throws Throwable { System.out.println ("before"); Integer proceed = (Integer) pdj.proceed (); System.out.println ("after"); return proceed+100; }
//4.返回后通知(需要方法正常运行才能通知)
//5.抛异常后通知
环绕通知@Around注意事项
1.环绕通知必须依赖形参ProceedingJoinPoint才能实现原始方法的调用,进而实现原始方法调用前后同时添加通知
2.通知中如果未使用ProceedingJoinPoint对原始方法进行调用将跳过原始方法的执行
3.对原始方法的调用可以不接受返回值,通知方法设置成void即可,如果接收返回值,必须设定为Object类型
4.原始方法的返回值如果是void,通知方法的返回值可以设置为void或object
5.由于无法预知原始方法运行后是否会抛出异常,因此环绕通知方法必须抛出Throwable对象
十八、Spring事务
事务的作用:在数据层保障一系列的数据库操作同成功同失败
SPring事务作用:在数据层或业务层保障一系列的数据库操作同成功同失败
Spring提供了一个接口两个方法和一个实现类用于事务
Spring开启事务
1.业务层中接口方法中添加注解,不要在实现类中添加,便于解耦
//配置当前接口方法具有事务 @Transactional public void transfer(String out,String in ,Double money) ;
2.实现事务方法
//配置事务管理器,mybatis使用的是jdbc事务 @Bean public TransactionManager transactionManager(DataSource dataSource){ DataSourceTransactionManager dm=new DataSourceTransactionManager (); dm.setDataSource (dataSource); return dm; }
3.在spring配置类中添加事务注解
@EnableTransactionManagement public class SpringConfig { }
Spring事务角色
事务管理员:发起事务方,在spring中通常指代业务层开启事务的方法(添加@Tranlation)
事务协调员:加入事务方,在Spring中通常指代数据层方法,也可以是业务层方法
REQUIRED默认的,事务管理员就是开启业务的业务层方法,事务协调员就是加入事务方,事务管理员开启了事务,事务协调员加入事务。没开就事务协调员新建
REQUIRED_NEW,事务管理员开启事务或不开,事务协调员就新建。如转账业务案例,事务生成失败,但是事务管理员的记录日志依旧成功运行。
SUPPORTS:事务管理员有开他就开,没开就不开
NOT_SUPPORTS:事务管理员有没有开,他都不开
NEVER:事务管理员开,他就报错,没开就不开
NESTED:设置保存点,事务回滚带保存点,就交给客户回滚

【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 震惊!C++程序真的从main开始吗?99%的程序员都答错了
· 【硬核科普】Trae如何「偷看」你的代码?零基础破解AI编程运行原理
· 单元测试从入门到精通
· 上周热点回顾(3.3-3.9)
· winform 绘制太阳,地球,月球 运作规律
2022-03-12 第三次作业。