Spring
核心概念
IoC(控制反转)
- 使用对象时,由主动new对象转换为由外部提供对象,此过程中对象创建控制权由程序转移到外部,此思想称为控制反转
- Spring提供了一个容器,称为Ioc容器,用来充当IoC思想中的外部
- IoC容器负责对象的创建,初始化等一系列工作,被创建或被管理的对象在IoC容器中统称为Bean
- Spring创建对象时,会把这些对象存放在一个集合中,这个集合就是SpringIoc容器
入门案例核心代码
配置文件
<bean id="bookDao" class="work.xlrong.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="work.xlrong.service.impl.BookServiceImpl"/>
Dao部分代码
public interface BookDao {
void save();
}
public class BookDaoImpl implements BookDao {
@Override
public void save() {
System.out.println("bookDao save");
}
}
Service部分代码
public interface BookService {
void save();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao = new BookDaoImpl();
@Override
public void save() {
System.out.println("bookService save");
bookDao.save();
}
}
测试
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
DI(依赖注入)
- 在容器中建立bean与bean之间的依赖关系的整个过程,称为依赖注入
入门案例核心代码
配置文件
<bean id="bookDao" class="work.xlrong.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="work.xlrong.service.impl.BookServiceImpl">
<!-- 配置service与dao的关系 -->
<!--property表示配置哪一个具体的属性-->
<property name="bookDao" ref="bookDao"/>
</bean>
Dao部分代码
public interface BookDao {
void save();
}
public class BookDaoImpl implements BookDao {
@Override
public void save() {
System.out.println("bookDao save");
}
}
Service部分代码
public interface BookService {
void save();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao;
@Override
public void save() {
System.out.println("bookService save");
bookDao.save();
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
测试
// 获取IoC容器
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = (BookDao) ctx.getBean("bookDao");
bookDao.save();
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
注
- Service中使用new形式创建的Dao对象不保留
- Service中需要的Dao对象根据提供方法的方式进入到Servlet中
- Service与Dao之间的关系是根据配置关联的
- Bean默认是单例的,因为防止创建过多对象
- 让测试用例有
Spring
支持:
@SpringBootTest
@RunWith(SpringRuner.class)
Spring
中的对象是单例
的
@Autowired和@Resource注解区别
@Resource
按照名称注入,@Autowired
按照类型注入,@Qualifire
指定要注入的bean
名称
适合交给容器进行管理的Bean
-
客观层对象
-
业务层对象
-
数据层对象
-
工具对象
不适合交给容器进行管理的Bean
- 封装实体的域对象
Bean实例化
bean本质上就是对象,创建bean使用构造方法完成
能new的对象就能配置bean,spring创建对象是使用类的无参构造创建的
方式1: 构造方法实例化bean
代码同上方
方式2: 使用静态工厂实例化bean
- 配置文件
<!-- 使用静态工厂示例化bean -->
<bean id="orderDao" class="work.xlrong.factory.OrderDaoFactory" factory-method="getOrderDao"/>
- dao部分代码
public interface OrderDao {
void save();
}
public class OrderDaoImpl implements OrderDao {
@Override
public void save() {
System.out.println("orderDao save");
}
}
- factory部分代码
public class OrderDaoFactory {
public static OrderDao getOrderDao() {
return new OrderDaoImpl();
}
}
- 测试
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
OrderDao orderDao = (OrderDao) ctx.getBean("orderDao");
orderDao.save();
方式3: 使用实例工厂实例化bean
- 配置文件
<!-- 使用实例工厂实例化bean -->
<bean id="userFactory" class="work.xlrong.factory.UserDaoFactory"/>
<bean id="userDao" factory-bean="userFactory" factory-method="getUserDao"/>
- Dao部分代码
public interface UserDao {
void save();
}
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("userDao save");
}
}
- Factory部分代码
public class UserDaoFactory {
public UserDao getUserDao() {
return new UserDaoImpl();
}
}
- 测试
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
UserDao userDao = (UserDao) ctx.getBean("userDao");
userDao.save();
方式4: 使用FactoryBean实例化Bean
- 配置文件
<!-- 使用FactoryBean实例化Bean -->
<bean id="userDao" class="work.xlrong.factory.UserDaoFactoryBean"/>
- Dao部分代码
public interface UserDao {
void save();
}
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("userDao save");
}
}
- FactoryBean部分代码
public class UserDaoFactoryBean implements FactoryBean<UserDao> {
/**
* 代替原始实例工厂中创建对象的方法
* @return
@throws Exception
*/
@Override
public UserDao getObject() throws Exception {
return new UserDaoImpl();
}
/**
* 获取对象的类型
*
* @return
*/
@Override
public Class<?> getObjectType() {
return UserDao.class;
}
/**
* 该对象是否是单例的
*
* @return
*/
@Override
public boolean isSingleton() {
return FactoryBean.super.isSingleton();
}
}
依赖注入方式
方式1: seter
- 配置文件
<bean id="userDao" class="work.xlrong.dao.impl.UserDaoImpl"/>
<bean id="bookDao" class="work.xlrong.dao.impl.BookDaoImpl"/>
<bean id="bookService" class="work.xlrong.service.impl.BookServiceImpl">
<property name="bookDao" ref="bookDao"/>
<property name="userDao" ref="userDao"/>
</bean>
- Dao部分代码
public interface UserDao {
void save();
}
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("userDao save");
}
}
public interface BookDao {
void save();
}
public class BookDaoImpl implements BookDao {
@Override
public void save() {
System.out.println("bookDao save");
}
}
- Service部分代码
public interface BookService {
void save();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao;
private UserDao userDao;
@Override
public void save() {
System.out.println("bookService save");
bookDao.save();
userDao.save();
}
public void setUserDao(UserDao userDao) {
this.userDao = userDao;
}
public void setBookDao(BookDao bookDao) {
this.bookDao = bookDao;
}
}
- 测试
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
- 存在成员变量时,代码改动为
<bean id="bookDao" class="work.xlrong.dao.impl.BookDaoImpl">
<property name="connectionNum" value="10"/>
<property name="databaseName" value="mysql"/>
</bean>
public class BookDaoImpl implements BookDao {
private int connectionNum;
private String databaseName;
public void setConnectionNum(int connectionNum) {
this.connectionNum = connectionNum;
}
public void setDatabaseName(String databaseName) {
this.databaseName = databaseName;
}
@Override
public void save() {
System.out.println("bookDao save..." + connectionNum + "..." + databaseName);
}
}
构造器注入
- 配置文件
<bean id="userDao" class="work.xlrong.dao.impl.UserDaoImpl"/>
<bean id="bookDao" class="work.xlrong.dao.impl.BookDaoImpl">
<constructor-arg name="connectionNum" value="10"/>
<constructor-arg name="databaseName" value="mysql"/>
</bean>
<bean id="bookService" class="work.xlrong.service.impl.BookServiceImpl">
<constructor-arg name="bookDao1" ref="bookDao"/>
<constructor-arg name="userDao1" ref="userDao"/>
</bean>
<bean id="userDao" class="work.xlrong.dao.impl.UserDaoImpl"/>
<bean id="bookDao" class="work.xlrong.dao.impl.BookDaoImpl">
<constructor-arg type="int" value="10"/>
<constructor-arg type="java.lang.String" value="mysql"/>
</bean>
<bean id="bookService" class="work.xlrong.service.impl.BookServiceImpl">
<constructor-arg name="bookDao1" ref="bookDao"/>
<constructor-arg name="userDao1" ref="userDao"/>
</bean>
<bean id="userDao" class="work.xlrong.dao.impl.UserDaoImpl"/>
<bean id="bookDao" class="work.xlrong.dao.impl.BookDaoImpl">
<constructor-arg index="0" value="10"/>
<constructor-arg index="1" value="mysql"/>
</bean>
<bean id="bookService" class="work.xlrong.service.impl.BookServiceImpl">
<constructor-arg name="bookDao1" ref="bookDao"/>
<constructor-arg name="userDao1" ref="userDao"/>
</bean>
- Dao部分代码
public interface UserDao {
void save();
}
public class UserDaoImpl implements UserDao {
@Override
public void save() {
System.out.println("userDao save");
}
}
public interface BookDao {
void save();
}
public class BookDaoImpl implements BookDao {
private int connectionNum;
private String databaseName;
public BookDaoImpl(int connectionNum, String databaseName) {
this.connectionNum = connectionNum;
this.databaseName = databaseName;
}
@Override
public void save() {
System.out.println("bookDao save..." + connectionNum + "..." + databaseName);
}
}
- Service部分代码
public interface BookService {
void save();
}
public class BookServiceImpl implements BookService {
private BookDao bookDao;
private UserDao userDao;
public BookServiceImpl(BookDao bookDao1, UserDao userDao1) {
this.bookDao = bookDao1;
this.userDao = userDao1;
}
@Override
public void save() {
System.out.println("bookService save");
bookDao.save();
userDao.save();
}
}
- 测试
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookService bookService = (BookService) ctx.getBean("bookService");
bookService.save();
总结
更推荐setter的方法
自动装配
按类型装配的话,名称需唯一
<bean id="bookService" class="work.xlrong.service.impl.BookServiceImpl" autowire="byType"/>
<bean id="bookService" class="work.xlrong.service.impl.BookServiceImpl" autowire="byName"/>
...
集合装配
- 配置文件
<bean id="bookDao" class="work.xlrong.dao.impl.BookDaoImpl">
<property name="array">
<array>
<value>100</value>
<value>200</value>
<value>300</value>
</array>
</property>
<property name="list">
<list>
<value>xlrong</value>
<value>hello</value>
<value>spring</value>
</list>
</property>
<property name="set">
<set>
<value>xlrong</value>
<value>hello</value>
<value>hello</value>
<value>spring</value>
</set>
</property>
<property name="map">
<map>
<entry key="country" value="中国"/>
<entry key="province" value="河南"/>
<entry key="city" value="郑州"/>
</map>
</property>
<property name="properties">
<props>
<prop key="country">中国</prop>
<prop key="province">河南</prop>
<prop key="city">郑州</prop>
</props>
</property>
</bean>
- Dao部分代码
public interface BookDao {
void save();
}
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;
}
@Override
public void save() {
System.out.println("bookDao 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);
}
}
- 测试
ApplicationContext ctx = new ClassPathXmlApplicationContext("applicationContext.xml");
BookDao bookDao = ctx.getBean(BookDao.class);
bookDao.save();
加载properties
步骤
- context -> 选property-placeholder
- 配置xml配置文件
- 配置property文件
- 引入配置文件中数据: ${}
需要加载多个配置文件
- 多个文件之间加逗号
<import resource="classpath:资源路径">
*.property
容器
创建容器方式
- 方式1:
ClassPathXmlApplicationContext
- 方式2:
FileSystemXmlApplicationContext
获取方式
- 方式1: 使用bean名称获取
BookDao bookDao = (Bookdao) ctx.getBean("bookDao");
- 方式2: 使用bean名称获取并指定类型
BookDao bookDao = ctx.getBean("bookDao", BookDao.class);
- 方式3: 使用bean类型获取(只能有一个相同类型)
BookDao bookDao = ctx.getBean(BookDao.class);
多配置文件时
- 方式1: 直接加载多个配置文件
new ClassPathXmlApplicationContext(".xml", ".xml");
- 方式2: 在核心配置文件中import多个配置文件,只加载核心配置文件
注解开发定义bean
常用注解/配置
@Component
: 声明一个组件,value是它的name@Repository
: 数据仓库<context:component-scan base-package="">
@Service
@AutoWired
@Controler
纯注解开发
注解
@Configuration
: 表明这是一个配置类@ComponentScan("")
: 扫描的包,如果有多个,用数组的方式添加@Scopr
: 作用范围单例还是多例
自动装配
注解
@AutoWired
@Qualifier("")
: 指定bean的名称、依赖于AutoWired@Value("")
: 简单类型的自动注入@PropertySource("")
: 指定数据源,写在配置类中,多文件使用大括号数组,不支持通配符
第三方bean管理
- 使用
@Bean
配置第三方bean - 使用
@ComponentScan
扫描 - 使用
@Import
Spring整合Mybatis+Junit
整合Junit常用注解
@RunWith(SpringJunit4ClassRunner.class)
:@ContextConfiguration(classes = SpringConfig.claaa)
: 核心配置文件
动态代理
在不修改代码的前提下对程序的功能进行增强,行为本身叫做面向切面编程或者AOP
大体步骤
- 获取原始对象(被代理的对象)
- 动态代理:
- 参数1: 被代理对象的类加载器
- 参数2: 被代理对象实现的接口们
- 参数3: 代理的行为
- 执行方法
AOP
面向切面编程,指导开发者如何组织程序结构
作用
在不惊动原始设计的基础上进行功能增强
核心概念
- 连接点: 程序执行过程中的任意位置,粒度为执行方法,抛出异常、设置变量等,在SpringAOP中,理解为方法的执行
- 切入点: 匹配连接点的式子,在SpringAOP中,一个切入点可以只描述一个具体方法,也可以匹配多个方法
- 一个具体方法: 某接口中的五形参无返回值的一个方法
- 匹配多个方法: 例: 所有的save方法,所有get开头的方法,所有以Dao结尾的接口中的任意方法,所有带有一个参数的方法
- 通知: 在切入点处执行的操作,也就是共性功能,在SpringAOP中,功能最终以方法的形式呈现
- 通知类: 定义通知的类
- 切面: 描述通知与切入点的对应关系
注解
@PointCut("execution(void ...method())")
: 切入点@Before("..()")
@Aspext
: 该类是AOP- 核心配置文件中:
@EnableAspectJAutoProxy
AOP工作流程
- Spring容器启动
- 读取所有切面中的切入点
- 初始化bean,判定bean对应的类中的方法是否匹配到任意切入点
- 匹配失败: 创建失败
- 匹配成功: 创建原始对象(目标对象)的代理对象
- 获取bean执行方法
- 获取bean,调用方法并执行,完成操作
- 获取的bean是代理对象时,根据代理对象的运行模式运行原始方法与增强的内容
AOP切入点表达式
- 切入点: 要进行增强的方法
- 切入点表达式: 要进行增强的方法的描述方式
语法格式
- 执行某包下的某接口中的无参数某方法
execution(void work.xlrong.dao.BookDao.update())
- 执行某包下某实现类中的某无参数方法
execution(void work.xlrong.dao.impl.BookDaoImpl.update())
常用通配符
-
*
: 单个独立的任意符号,可以独立出现,也可以作为前缀或者后缀的匹配符出现 -
..
: 多个连续的任意符号,可以独立出现,常用于简化包名与参数的书写 -
+
: 常用于匹配子类类型 -
在切入点中,可以使用与或非符号
&& / and
: 与|| / or
: 或!
: 非
AOP通知类型
AOP通知描述了抽取的共性问题,根据共性功能抽取的位置不同
AOP的5种通知
- 前置通知:
@Before
- 后置通知:
@After
- 环绕通知: 注意返回值
@Around("pt()")
public void around(ProceedingJoinPoint pjp) throws Throwable {
System.out.println("before");
// 表示对原始操作的调用
pjp.proceed();
System.out.println("after");
}
- 返回后通知:
- 抛出异常后通知:
Spring事物
在数据层保障一系列的数据库操作同成功同失败
在数据层或业务层保障一系列的数据库操作同成功同失败
注解
@Transactional
: 开启事务
工具类
- 可以用于
MD5
加密:
String md5DigestAsHex = DigestUtils.md5DigestAsHex((password + salt).getBytes());