Spring框架总结
Spring是一个轻量级的容器,它的核心是 IoC(控制反转) 和 AOP(面向切面编程)
IoC 控制反转
将对象的创建权限交给Spring管理,通过Spring容器获取对象的方式被成为控制反转
- 基于 XML 方式
<bean id="userService" class="com.qikux.service.impl.UserServiceImpl" />
- 基于注解方式
# @Controller : 将控制层对象交给 Spring管理
# @Service : 将业务层对象交给 Spring管理
# @Repository : 将持久层对象交给 Spring管理
# @Component : 将 其他层对象交给 Spring管理 ,例如 切面
@Service
public class UserServiceImpl implement UserService{
...
}
Spring容器需要使用注解进行IoC, 那么需要启用扫描指定的包 <context:component-scan />
- 基于 JavaConfig
# @Configuration : 标记一个类是 配置 类 ,使用 @Bean 管理 对象
@Configuration
public class RootConfig {
@Bean
public UserService userService() {
return new UserServiceImpl() ;
}
}
DI 依赖注入
给 Spring 管理的对象的属性 自动注入值的过程 被称为 依赖注入
实现方式
- 属性注入
- 构造注入
- 静态工厂注入
- 实例工厂注入
属性注入
要求Spring管理的对象,需要提供无参构造方法、需要提供 set方法 (注解除外)
相对比较灵活
- 基于 xml 的注入方式
<bean id="userDao" class="com.qikux.dao.impl.UserDaoImpl" />
<bean id="userService" class="com.qikux.service.impl.UserServiceImpl">
<property name="userDao" ref="userDao">
</bean>
- 基于 注解 的注入方式
@Service
public class UserServiceImpl implement UserService{
private UserDao userDao ;
@Autowired
public void setUserDao(UserDao userDao) {
this.userDao = userDao ;
}
}
- 基于 JavaConfig的注入方式
@Configuration
public class RootConfig {
@Bean
public UserService userService(UserDao userDao) {
return new UserServiceImpl(userDao) ;
}
}
不同数据类性 的注入方式
- 字面量 (基本数据类型 + 包装类 + 字符串)
- xml方式
<property name="age" value="10">
通过 value 属性 注入, name=“age” 中的 age 指定的是 对象中的 setAge 方法对应的属性
- 注解注入
@Value("10")
@Value("${age}")
${age} 代表 从 properties 配置中读取的值
- 引用bean
- xml方式
<property name="userDao" ref="userDao">
通过 ref 引用一个 Spring管理的对象的BeanId
- 注解注入 (要求掌握三个注入的使用区别)
-
@Autowired : (这个注解是属业spring的)根据类型注入Spring管理的某个对象,默认情况下必须要求依赖对象必须存在,如果要允许null值,可以设置它的required属性为false,如果容器中类型有多个,会产生异常,可以配置@Qualifier 指定 注入的bean名称
-
@Resource : 这个注解属于J2EE的) 默认按照名称进行装配,名称可以通过name属性进行指定,如果没有指定name属性,当注解写在字段上时,默认取字段名进行安装名称查找,如果注解写在setter方法上默认取属性名进行装配。当找不到与名称匹配的bean时才按照类型进行装配。但是需要注意的是,如果name属性一旦指定,就只会按照名称进行装配。
-
@Injected : 是 JSR-330 规范提供的依赖包 (javax.inject), 按.照类型注入,可以通过@Named 指定注入的 bean名称
三者区别可以参考@Autowired、@Inject、@Resource三者区别 -
List集合
<property name="list">
<list>
<value /> | <ref />
</list>
</property>
- Set 集合
和 List集合用法相同,只需要把 list标签 换成 set 标签即可
- 数组
和 List集合用法相同,只需要把 list标签 换成 array 标签即可
- Map 集合
<property name="map">
<map>
<entry key="" value="" value-type=""></entry>
</map>
</property>
entry 中属性有 key, key-ref, value , value-ref, value-type
- Properties 注入
<property name="attrs">
<props>
<prop key="email">huo@qq.com</prop>
</props>
</property>
- Null 注入
<property name="xxx">
<null />
</property>
- 特殊字符注入
<property name="xxx">
<value><![CDATA[特殊字符]]></value>
</property>
构造注入
必须提供有参构造,根据有参构造,完成对象的属性赋值
不是很灵活,但适用于一成不变
的对象, 可以尽可能保证某个属性必须存在值
- XML注入
<bean id="userDao" class="com.qikux.dao.impl.UserDaoImpl" />
<bean id="userService" class="com.qikux.service.impl.UserServiceImpl">
<constructor-arg name="id" value="2" />
</bean>
constructor-arg 标签中有 index , name, value , ref, type 等属性
- 注解注入
@Service
public class UserServiceImpl implement UserService{
private UserDao userDao ;
@Autowired
public UserServiceImpl(UserDao userDao) {
this.userDao = userDao ;
}
}
构造注入 只能使用 @Autowired 注解 ,如果一个类中有且只有一个构造方法(有参),那么可以省略 @Autowired
静态工厂注入
<bean id="user" class="com.qikux.factory.UserFactory" factory-method="getUser" />
getUser 是 UserFactory中的静态方法,且返回一个 User方法, getUser方法不能有任何参数
实例工厂注入
<bean id="factory" class="com.qikux.factory.UserFactory" />
<bean id="user" factory-bean="factory" factory-method="getUser" />
getUser 是 UserFactory中的实例方法,且返回一个 User方法, getUser方法不能有任何参数
AOP
面向切面编程、是对面向对象的扩展和补充,通过横切的方式向目标对象的某个切点织入逻辑
AOP的实现手段是通过 动态代理,默认采用 JDK动态代理,也可以使用 cglib 动态代理
好处
在不修改原有代码的基础上,对程序进行增强,是一种无侵入式的编程方式
能做什么 ?
- 事务管理
- 日志记录
- 性能检测
实现方式
-
advice
-
aspectj
依赖 jar
aspectjwearver
aspectjrt
Advice
- MethodBeforeAdvice : 前置通知
- AfterReturningAdvice : 后置通知
- MethodInterceptor : 环绕通知
- ThrowsAdvice : 异常抛出增强
使用 Aspectj 配置 Advice
- 基于 XML 的配置
- 使用 aop 命名空间,启用 aspectj 自动代理
<aop:aspectj-autoproxy />
默认采用JDK动态代理,可以设置 proxy-target-class 属性为 true, 启用 cglib 代理
- 将 切面类 交给 Spring管理
<bean id="logAspect" class="....." />
- 将 切面类 ,通过 切点表达式 绑定到 目标对象上
<aop:config>
<aop:pointcut id="pt" expression="execution(....)"/>
<aop:advisor advice-ref="logAspect" pointcut-ref="pt" />
</aop:config>
Aspectj 实现切面
- 基于 XML 的配置
- 编写一个 增强类
public class LogAspectj {
public void before(JointPoint jp) {
...
}
}
- 配置 增强类
<bean id="logAspect" class="....." />
- 使用 aop 命名空间,启用 aspectj 自动代理
<aop:aspectj-autoproxy />
4.将 切面类 ,通过 切点表达式 绑定到 目标对象上
<aop:config>
<aop:aspect ref="logAspect">
<aop:pointcut id="pt" expression="execution(....)"/>
<aop:before method="before" pointcut-ref="pt"" />
</aop:aspect>
</aop:config>
- 基于注解的配置
- @Before : 前置通知
- @AfterReturning : 后置通知
- @Around : 环绕通知
- AfterThrowing : 异常抛出通知
@Before , @AfterReturning, @AfterThrowing 注释的方法第一个参数都可以住 JoinPoint 对象
@Around 注释的方法 可以注入一个 @ProceedingJoinPoint, 方法必须返回 Object
- 编写一个增强类
@Aspect
@Component
public class LogAspectj {
@Before("execution(....)")
public void before(JointPoint jp) {
...
}
}
- 启用 自动代理
<aop:aspectj-autoproxy />
- 基于 JavaConfig 的配置
- 配置类上,启用自动代理
@EnableAspectJAutoProxy
- 配置切面类
@Aspect
@Component
public class LogAspectj {
@Before("execution(....)")
public void before(JointPoint jp) {
...
}
}
Spring 整合 MyBatis
环境:spring-orm.jar, mybatis.jar , mysql-connector-java.jar, mybatis-spring.jar , druid.jar
- XML 配置
- 读取 properties配置文件
<context:property-placeholder file-encoding="utf-8"
location="classpath:jdbc.properties"
local-override="true"/>
- 配置 数据源
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="..."></property>
<property name="url" value="..."></property>
<property name="username" value="..."></property>
<property name="password" value="..."></property>
</bean>
- 配置 SqlSessionFactory
<bean id="sqlSessionFactory" class="org.mybatis.spring.SqlSessionFactoryBean" >
<property name="dataSource" ref="dataSource"/>
<property name="configLocation" value="classpath:mybatis-config.xml"/>
<property name="mapperLocations" value="classpath*:com/**/mapper/*.xml"/>
</bean>
- 扫描 持久层接口 MapperScannerConfigurer
<mybatis:scan base-package="com.qikux.dao" />
- JavaConfig 的配置
@Configuration
@PropertySource("classpath:jdbc.properties")
@MapperScan("com.qikux.dao")
public class MyBatisAutoConfig {
@Autowired
private Environment env ;
/**
* 配置数据源
* @return
*/
@Bean("dataSource")
@Profile("dev") // 默认环境是 default
public DataSource dataSource_dev() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(env.getProperty("db.driver"));
ds.setUrl(env.getProperty("db.url"));
ds.setUsername(env.getProperty("db.username"));
ds.setPassword(env.getProperty("db.password"));
ds.setMaxActive(Integer.valueOf(env.getProperty("db.maxActive")));
return ds ;
}
@Bean("dataSource")
@Profile("pro")
public DataSource dataSource_pro() {
DruidDataSource ds = new DruidDataSource();
ds.setDriverClassName(env.getProperty("pro.db.driver"));
ds.setUrl(env.getProperty("pro.db.url"));
ds.setUsername(env.getProperty("pro.db.username"));
ds.setPassword(env.getProperty("pro.db.password"));
ds.setMaxActive(Integer.valueOf(env.getProperty("pro.db.maxActive")));
return ds ;
}
/**
* 配置 SqlSessionFactory
*/
@Bean
public SqlSessionFactory sqlSessionFactory(@Qualifier("dataSource") DataSource dataSource) throws Exception {
// 创建一个 SqlSessionFactoryBean 对象
SqlSessionFactoryBean bean = new SqlSessionFactoryBean();
// 整合 数据源
bean.setDataSource(dataSource);
// 整合 mybatis配置文件
// 读取 classpath下 某一个配置文件
bean.setConfigLocation(new ClassPathResource("/mybatis-config.xml"));
// 批量读取 classpath下的资源文件
PathMatchingResourcePatternResolver resolver = new PathMatchingResourcePatternResolver();
Resource[] resources = resolver.getResources("classpath*:com/**/mapper/*.xml");
// 整合 映射文件
bean.setMapperLocations(resources);
return bean.getObject() ;
}
}
Spring 配置事务管理
- XML的配置
- 配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref="dataSource"></property>
</bean>
- 配置 事务切面
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="query*" propagation="SUPPORTS" isolation="READ_COMMITTED" read-only="true"
rollback-for="java.lang.Throwable"/>
<tx:method name="*" rollback-for="java.lang.Throwable" />
</tx:attributes>
</tx:advice>
- 配置 切入点
<aop:config>
<aop:pointcut id="pt" expression="execution(* com.qikux.service..*.*(..))"/>
<aop:advisor advice-ref="txAdvice" pointcut-ref="pt"/>
</aop:config>
- 基于注解的配置
- 配置事务管理器
<bean id="transactionManager" class="org.springframework.jdbc.datasource.DataSourceTransactionManager" >
<property name="dataSource" ref="dataSource"></property>
</bean>
- 启用事务注解支持
<tx:annotation-driven transaction-manager="transactionManager"/>
- 在业务层类/方法上,添加 @Transactional 注解
- JavaConfig的配置
- 配置类的编写
@Configuration
@EnableTransactionManagement
public class TransactionAutoConfig {
@Resource
private DataSource dataSource ;
@Bean
public TransactionManager transactionManager() {
return new DataSourceTransactionManager(dataSource) ;
}
}
2.在业务层类/方法上,添加 @Transactional 注解