Spring
-
==Spring的IOC/DI==
-
==Spring的AOP==
-
==AOP的具体应用,事务管理==
-
==IOC/DI的具体应用,整合Mybatis==S
1.1IOC
IOC:控制反转,控制反转的是对象的创建权
DI:依赖注入,绑定对象与对象之间的依赖关系
1.1.1bean的配置
<!--bean标签标示配置bean id属性标示给bean起名字 class属性表示给bean定义类型 name标识配置bean的多个别名 scope表示bean的作用范围,singleton默认为单例(创建出的两个bean地址相同),prototype为非单例 --> <bean id="bookService" name="service,bookService2" class="com.example.service.impl.BookServiceImpl" scope="prototype"> <!--配置server与dao的关系--> <!--property标签表示配置当前bean的属性 name属性表示配置哪一个具体的属性 ref属性表示参照哪一个bean --> <property name="bookDao" ref="bookDao"/> </bean>
1.1.2bean的实例化(创建)
1.构造方法: public interface BookDao { public void save(); } public class BookDaoImpl implements BookDao {‘ //可以提供无参的构造方法,因为每一个类默认都会提供一个无参构造函数 public BookDaoImpl() { System.out.println("book dao constructor is running ...."); } public void save() { System.out.println("book dao save ..."); } } <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"/> ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); BookDao bookDao = (BookDao) ctx.getBean("bookDao"); bookDao.save(); 2.静态工厂: //静态工厂创建对象 public class OrderDaoFactory { public static OrderDao getOrderDao(){ return new OrderDaoImpl(); } } //通过静态工厂创建对象 OrderDao orderDao = OrderDaoFactory.getOrderDao(); orderDao.save(); spring实例化静态工厂: <bean id="orderDao" class="com.itheima.factory.OrderDaoFactory" factory-method="getOrderDao"/> ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); OrderDao orderDao = (OrderDao) ctx.getBean("orderDao"); orderDao.save(); 3.实例化工厂: //和静态工厂的工厂类不一样的地方是方法不是静态方法 public class UserDaoFactory { public UserDao getUserDao(){ return new UserDaoImpl(); } } //创建实例工厂对象 UserDaoFactory userDaoFactory = new UserDaoFactory(); UserDao userDao = userDaoFactory.getUserDao(); userDao.save(); spring实现实例化工厂: <bean id="userFactory" class="com.itheima.factory.UserDaoFactory"/> <bean id="userDao" factory-bean="userFactory" factory-method="getUserDao" /> 4.FactoryBean: //实现FactoryBean接口 public class EmpDaoFactory implements FactoryBean { //代替原始实例工厂中创建对象的方法,返回实例化bean对象 @Override public Object getObject() throws Exception { return new EmpDaoImpl(); } //返回所创建类的Class对象 @Override public Class<?> getObjectType() { return EmpDao.class; } //创建bean是否单例 @Override public boolean isSingleton() { return FactoryBean.super.isSingleton(); } } <bean id="userDao" class="com.itheima.factory.UserDaoFactoryBean"/>
1.1.3.bean的生命周期
bean对象从创建到销毁的整体过程(init==>destory)
public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); } //表示bean初始化对应的操作 public void init(){ System.out.println("init..."); } //表示bean销毁前对应的操作 public void destory(){ System.out.println("destory..."); } } public class BookServiceImpl implements BookService, InitializingBean, DisposableBean { private BookDao bookDao; public void setBookDao(BookDao bookDao) { System.out.println("set ....."); this.bookDao = bookDao; } public void save() { System.out.println("book service save ..."); bookDao.save(); } public void destroy() throws Exception { System.out.println("service destroy"); } //属性配置后执行 public void afterPropertiesSet() throws Exception { System.out.println("service init"); } } //在配置文件中的bean标签中添加init-method和destroy-method属性 <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl" init-method="init" destroy-method="destory"/> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl"> <property name="bookDao" ref="bookDao"/> </bean> 运行结果: init... //先bean的初始化 set ..... //bean的注入 service init //业务操作 book service save ... book dao save ... service destroy //业务结束 destory... //bean销毁
1.2DI
1.2.1依赖注入
1.setter注入: public class BookServiceImpl implements BookService { //引用数据类型 private BookDao bookDao; //简单数据类型 private Integer age; public void setBookDao(BookDao bookDao) { this.bookDao = bookDao; } public void setAge(Integer age) { this.age = age; } @Override public void save() { System.out.println("book service save"); bookDao.save(); System.out.println(age); } } //使用property标签和ref,value属性注入 <bean id="bookDao" class="com.example.dao.impl.BookDaoImpl"></bean> <bean id="bookService" class="com.example.service.impl.BookServiceImpl"> <property name="bookDao" ref="bookDao"></property> <property name="age" value="10"></property> </bean> 2.构造器注入: public class UserServiceImpl implements UserService { private UserDao userDao; private Integer age; public UserServiceImpl(UserDao userDao,Integer age){ this.userDao = userDao; this.age = age; } @Override public void save() { System.out.println("user service save"); userDao.save(); System.out.println(age); } } //使用constructor-arg标签和ref,value属性注入 <bean id="userDao" class="com.example.dao.impl.UserDaoImpl"></bean> <bean id="userService" class="com.example.service.impl.UserServiceImpl"> <constructor-arg name="userDao" ref="userDao"></constructor-arg> <constructor-arg name="age" value="10"></constructor-arg> </bean> 构造器其他注入方式(按照实际情况使用): //方式一:删除name属性,添加type属性,按照类型注入 <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> <constructor-arg type="int" value="10"/> <constructor-arg type="java.lang.String" value="mysql"/> </bean> //方式二:删除type属性,添加index属性,按照索引下标注入,下标从0开始 <bean id="bookDao" class="com.itheima.dao.impl.BookDaoImpl"> <constructor-arg index="1" value="100"/> <constructor-arg index="0" value="mysql"/> </bean> 注:如果有必要可以两者同时使用,使用构造器注入完成强制依赖的注入,使用setter注入完成可选依赖的注入 3.自动配置: 自动装配用于引用类型依赖注入,不能对简单类型进行操作 需要注入属性的类中对应属性的setter方法不能省略 自动装配优先级低于setter注入与构造器注入,同时出现时自动装配配置失效 按照类型注入: <bean class="com.itheima.dao.impl.BookDaoImpl"/> <!--autowire属性:开启自动装配,通常使用按类型装配--> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byType"/> 按照名称注入: <bean class="com.itheima.dao.impl.BookDaoImpl"/> <!--autowire属性:开启自动装配,通常使用按类型装配--> <bean id="bookService" class="com.itheima.service.impl.BookServiceImpl" autowire="byName"/> 4.集合注入: public class BookDaoImpl implements BookDao { private int[] array; private List<String> list; private Set<String> set; private Map<String,String> map; private Properties properties; //setter....方法省略 public void save() { System.out.println("book dao save ..."); } } 数组: <property name="array"> <array> <value>100</value> <value>200</value> <value>300</value> </array> </property> set,list一次类推...... map: <property name="map"> <map> <entry key="country" value="china"/> <entry key="province" value="henan"/> <entry key="city" value="kaifeng"/> </map> </property> properties: <property name="properties"> <props> <prop key="country">china</prop> <prop key="province">henan</prop> <prop key="city">kaifeng</prop> </props> </property> 注:property标签表示setter方式注入,构造方式注入constructor-arg标签内部也可以写<array>、<list>、<set>、<map>、<props>标签
1.3IOC&DI管理第三方bean
加载druid: <!--管理DruidDataSource对象--> <bean class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="com.mysql.jdbc.Driver"/> <property name="url" value="jdbc:mysql://localhost:3306/spring_db"/> <property name="username" value="root"/> <property name="password" value="root"/> </bean> ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml"); DataSource dataSource = (DataSource) ctx.getBean("dataSource"); System.out.println(dataSource); xml读取外部配置文件: 1.开启context命名空间 <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"> </beans> 2.添加context标签: <context:property-placeholder location="jdbc.properties"/> 3.通过${key}读取数据: <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource"> <property name="driverClassName" value="${jdbc.driver}"/> <property name="url" value="${jdbc.url}"/> <property name="username" value="${jdbc.username}"/> <property name="password" value="${jdbc.password}"/> </bean> 注:system-properties-mode="NEVER"关闭系统加环境变量 <context:property-placeholder location="jdbc.properties" system-properties-mode="NEVER"/> 读取多个配置文件: <!--方式一 --> <context:property-placeholder location="jdbc.properties,jdbc2.properties"/> <!--方式二--> <context:property-placeholder location="*.properties"/> <!--方式三 --> <context:property-placeholder location="classpath:*.properties"/> <!--方式四--> <context:property-placeholder location="classpath*:*.properties"/>
1.4核心容器
-
使用BeanFactory创建的容器是延迟加载
-
使用ApplicationContext创建的容器是立即加载
获取Bean的三种方式
-
getBean("名称"):需要类型转换
-
getBean("名称",类型.class):多了一个参数
-
getBean(类型.class):容器中不能有多个该类的bean对象
1.5使用注解开发bean
1.使用注解定义bean:
@Component("bookDao") public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..." ); } } //扫描注解 <context:component-scan base-package="com.itheima"/>
2.使用配置类删除配置文件:
@Configuration @ComponentScan({"com.example.dao","com.example.service"}) //扫描bean @Import({JdbcConfig.class}) //使用import注解手动导入需要加载的配置类 @PropertySource({"application.properties"}) //扫描配置问价 public class SpringConfig { } AnnotationConfigApplicationContext applicationContext = new AnnotationConfigApplicationContext(SpringConfig.class); BookService bookServiceImpl = applicationContext.getBean("bookServiceImpl", BookService.class); bookServiceImpl.save(); applicationContext.close();
3.使用注解开发bean的生命周期:
//bean的作用范围 @Scope("prototype") public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); } } //bean的初始化和销毁 public class BookDaoImpl implements BookDao { public void save() { System.out.println("book dao save ..."); } @PostConstruct //在构造方法之后执行,替换 init-method public void init() { System.out.println("init ..."); } @PreDestroy //在销毁方法之前执行,替换 destroy-method public void destroy() { System.out.println("destroy ..."); } }
4.使用注解进行依赖注入:
@Autowired @Qualifier("bookDao1") //多个同类型bean,则根据名称注入 private BookDao bookDao //一般适用于读取配置文件属性 @Value("${name}") private String name; @PropertySource("jdbc.properties") public class SpringConfig { }
5.使用注解管理第三方bean:
@Configuration public class JdbcConfig { //读取配置文件注入 @Value("${spring.datasource.driver-class-name}") private String driverClassName; @Value("${spring.datasource.url}") private String url; @Value("${spring.datasource.password}") private String password; @Value("${spring.datasource.username}") private String username; @Bean public DataSource GetDataSource(BookDao bookDao){ //构建DataSource对象的时候,需要用到BookDao对象 System.out.println(bookDao); DruidDataSource ds = new DruidDataSource(); ds.setDriverClassName(driverClassName); ds.setUrl(url); ds.setPassword(password); ds.setUsername(username); return ds; } } @Configuration @ComponentScan("com.itheima.dao") @Import({JdbcConfig.class}) //使用import注解手动导入需要加载的配置类 @PropertySource({"application.properties"}) public class SpringConfig { } //第三方bean AnnotationConfigApplicationContext ctx1 = new AnnotationConfigApplicationContext(JdbcConfig.class); DataSource DataSource = ctx1.getBean(DataSource.class); System.out.println(DataSource);
1.6AOP
AOP在JavaWeb阶段已经详细学过,此次只增加其他内容
使用AOP获取数据参数异常:
1.获取参数: @Around("pt()") public Object around(ProceedingJoinPoint pjp)throws Throwable { Object[] args = pjp.getArgs(); System.out.println(Arrays.toString(args)); args[0] = 666; Object ret = pjp.proceed(args); return ret; } 2.获取返回值: @AfterReturning(value = "pt()",returning = "ret") public void afterReturning(Object ret) { System.out.println("afterReturning advice ..."+ret); } 3. 获取异常: @AfterThrowing(value = "pt()",throwing = "t") public void afterThrowing(Throwable t) { System.out.println("afterThrowing advice ..."+t); }
1.7事务
开启事务: 1.添加注解: @Transactional public void transfer(String out,String in ,Double money) { accountDao.outMoney(out,money); int i = 1/0; accountDao.inMoney(in,money); } 2.配置事务管理器: //配置事务管理器,mybatis使用的是jdbc事务 @Bean public PlatformTransactionManager transactionManager(DataSource dataSource){ DataSourceTransactionManager transactionManager = new DataSourceTransactionManager(); transactionManager.setDataSource(dataSource); return transactionManager; } 3.开启事务驱动: @EnableTransactionManagement public class SpringConfig { }
事务角色:
事务属性:
-
timeout:设置超时时间单位秒,在多长时间之内事务没有提交成功就自动回滚,-1表示不设置超时时间。
-
rollbackFor:当出现指定异常进行事务回滚
Spring的事务只会对Error异常
和RuntimeException异常
及其子类进行事务回顾
指定事务回滚:@Transactional(rollbackFor = {IOException.class})
-
noRollbackFor:当出现指定异常不进行事务回滚
事务的传播行为:
@Autowired private LogDao logDao; //propagation设置事务属性:传播行为设置为当前操作需要新事务 @Transactional(propagation = Propagation.REQUIRES_NEW) public void log(String out,String in,Double money ) { logDao.log("转账操作由"+out+"到"+in+",金额:"+money); } //此时不管事务1和事务2是否回滚,日志事务会一直执行下去