Spring介绍
简介
- Spring框架是一个帮我们管理对象的容器,可以看做是对象的管家。
- Spring一站式框架:正是由于Spring框架的性质是属于容器性质的,容器中装什么对象,就有什么功能,所以可以一站式,spring不仅不排斥其他框架,还可以帮其他框架管理对象
spring中名词解释
- IOC(inverse of Control):控制反转
将对象的创建方式反转了,从由自己创建,反转为由spring容器创建,以前对象的创建和维护以及依赖关系都由我们自己来做,现在可以将这些工作交给程序来做 - DI(dependency injection):依赖注入
实现IOC需要DI支持
注入方式:set注入、构造注入、字段注入
注入类型:8大数据类型、应用数据类型
Spring搭建
步骤:
- 导包
- 创建实体类
- 创建配置文件(文件名和位置无要求,但是最好名为applicationContext.xml,并且放置在src下
【】导入约束
【】将实体类的对象交给spring容器管理
//name:spring创建对象的名称 class:对应实体类的全类名
<bean name="user" class=""></bean>
测试代码:
//创建容器
ApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
//从容器中取出对象
User u = ac.getBean("user")
Spring的配置详解
bean元素
/*
name:spring创建对象的名称
class:对应实体类的全类名
scope:
singleton(默认值):创建单例对象,在spring容器中只会存在一个实例
prototype:多例原型,每次再获得时才会被创建,而且每次得到的对象都是新的
init-method(填初始化方法的方法名):spring会在对象创建后立即调用该方法
destory-method(填销毁方法的方法名):在spring容器关闭并销毁所有对象前调用该方法
*/
<bean name="user" class="" scope="singleton" init-method="" destory-method="" ></bean>
Spring创建对象的方式
- 空参构造方式(调用无参的构造方法)
- 静态工厂方式(了解)
- 实例工厂方式(了解)
spring的分模块配置
//resource:另一个xml配置文件的路径
<import resource="" />
Spring的属性注入
set方法注入
<bean name="user" class"">
//值类型注入
//将User对象中名为name的属性值赋值为张三
<property name="name" value="张三"></property>
<property name="age" value="18"></property>
//引用类型注入
//将对象名为car的对象赋值给User对象中的Car类型的引用变量
<property name="car" ref="car"></property>
</bean>
构造函数注入
<bean>
/*
name:构造函数的函数名
index:构造函数的参数索引
type:参数类型
*/
<constructor-arg name="" index="" type=""></constractor>
<constructor-arg name="" index="" ref=""></constractor>
</bean>
spl注入
复杂类型注入
- 数组
<property name="array">
<array>
<value>Tom</value>
<value>jery</value>
<ref bean="car ">
</array>
</property>
- List
<property name="list">
<list>
<value>Tom</value>
<value>jery</value>
<ref bean="car ">
</list>
</property>
- Map
<property name="map">
<map>
<entry key="" value=""></entry>
<entry key-ref="" value-ref=""></entry>
</map>
</property>
- Properties
<property name="properties">
<props>
<prop key="driverClass">com.jdbc.mysql.Driver</prop>
</props>
</property>
Spring 的注解配置
- 步骤:
- 导包
- 在主配置文件中导入约束
- 在配置文件中开启使用注解
//指定扫描cn.itcast.bean包下的注解
//注意:扫描包时,会自动扫描指定包的子孙包
<context:component-scan base-package="cn.itcast.bean"></context:component-scan>
- 在类中完成注解配置
- 将对象注册到容器中
//四个注解效果一样
@Component("user")
//@Service("user1") service层注解
//@Controller("user2") web层注解
//@Repository("user3") dao层注解
@Scope(scopeName="prototype")//指定对象作用范围
public class User {
@Value("tom") //通过反射的Field赋值,破坏了封装性
private String name;
private Integer age;
//@Autowired //自动装配
//问题:如果匹配多个类型一致的对象,将无法选择注入哪一个对象
//@Qualifier("car")//使用Qualifier注解告诉spring容器自动装配哪个名称的对象
@Resource(name="car")//手动注入
private Car car;
@Value("tom") //通过set方法赋值
public void setName(String name) {
this.name = name;
}
public void setAge(Integer age) {
this.age = age;
}
public void setCar(Car car) {
this.car = car;
}
@PostConstruct //初始化方法,在对象被创建后调用
public void init(){
System.out.println("我是初始化方法");
}
@PreDestroy //销毁方法,在销毁之前调用
public void destory(){
System.out.println("我是销毁方法");
}
}
- spring与Junit整合测试
- 导包
- 配置注解
//帮我们创建容器
@Runwith(SpringJunit4ClassRunner.class)
@ContextConfiguration("classpath:ApplicationContext.xml");
@Test
public void fun(){
}
Spring中的AOP
- AOP思想介绍:纵向重复,横向抽取(如过滤器解决乱码问题)
- Spring中AOP概念:以前需要使用动态代理产生代理对象,现在spring能够帮我们生成代理对象
- Spring实现AOP的原理:
- 动态代理优先(被代理对象必须要实现接口才能产生代理对象)
- 使用cglib代理(不要接口,可以对任何类进行代理。代理的原理是对目标对象进行继承代理。如果目标对象被final修饰,则不能完成代理)
- AOP中的名词
- Joinpoint(连接点):目标对象中所有可以被增强的方法。
- Pointcut(切入点):目标对象已经增强的方法。
- Advice(通知/增强):增强的代码
- Target(目标对象):被代理对象
- weaving(织入):将通知应用到切入点的过程
- Proxy(代理):将通织入到目标对象后生成的代理对象
- aspect(切面):切入点+通知
#Spring中的AOP演示.
xml配置
- 导包
- 准备目标对象
public class UserServiceImpl implements UserService {
@Override
public void add() {
System.out.println("添加");
}
@Override
public void delete() {
System.out.println("删除");
}
@Override
public void update() {
System.out.println("更新");
}
@Override
public void find() {
System.out.println("查找");
}
}
- 准备通知
public class MyAdvice {
public void before(){
System.out.println("这是前置通知");
}
public void around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("这是环绕通知的前半部分");
pjp.proceed();
System.out.println("这是环绕通知的后半部分");
}
public void after(){
System.out.println("这是after后置通知");
}
public void afterRunning(){
System.out.println("这是afterRunning后置通知");
}
public void afterException(){
System.out.println("出现异常了");
}
}
- 配置织入
<!-- 配置目标对象 -->
<bean name="userService" class="cn.itcast.service.UserServiceImpl"></bean>
<!-- 配置通知对象 -->
<bean name="myAdvice" class="cn.itcast.d_springaop.MyAdvice"></bean>
<!-- 将通知织入切点 -->
<aop:config>
<!-- public void cn.itcast.service.UserServiceImpl.add() -->
<!-- void cn.itcast.service.UserServiceImpl.add() -->
<!-- * cn.itcast.service.UserServiceImpl.add() -->
<!-- * cn.itcast.service.UserServiceImpl.*() -->
<!-- * cn.itcast.service.UserServiceImpl.*(..) -->
<!-- * cn.itcast.service.*ServiceImpl.*(..) -->
<!-- * cn.itcast.service..*ServiceImpl.*(..) -->
<aop:pointcut expression="* cn.itcast.service..*ServiceImpl.*(..)" id="pc"/>
<aop:aspect ref="myAdvice">
<aop:before method="before" pointcut-ref="pc"/>
<aop:after method="after" pointcut-ref="pc"/>
<aop:around method="around" pointcut-ref="pc"/>
<aop:after-returning method="afterRunning" pointcut-ref="pc"/>
<aop:after-throwing method="afterException" pointcut-ref="pc"/>
</aop:aspect>
</aop:config>
注解配置
- 导包
- xml中配置通知对象和目标对象,并在xml中开启使用注解
<!-- 配置目标对象 -->
<bean name="userService" class="cn.itcast.service.UserServiceImpl"></bean>
<!-- 配置通知对象 -->
<bean name="myAdvice" class="cn.itcast.e_annotationaop.MyAdvice"></bean>
<!-- 开启使用注解完成织入 -->
<aop:aspectj-autoproxy></aop:aspectj-autoproxy>
- 在通知类中使用注解
@Aspect //表示该类是一个通知类
public class MyAdvice {
@Pointcut("execution(* cn.itcast.service.*ServiceImpl.*(..))")
public void pc(){};
@Before("MyAdvice.pc()")
public void before(){
System.out.println("这是前置通知");
}
@Around("MyAdvice.pc()")
public void around(ProceedingJoinPoint pjp) throws Throwable{
System.out.println("这是环绕通知的前半部分");
pjp.proceed();
System.out.println("这是环绕通知的后半部分");
}
@After("MyAdvice.pc()")
public void after(){
System.out.println("这是after后置通知");
}
@AfterReturning("MyAdvice.pc()")
public void afterRunning(){
System.out.println("这是afterRunning后置通知");
}
@AfterThrowing("MyAdvice.pc()")
public void afterException(){
System.out.println("出现异常了");
}
}
Spring管理事物的属性介绍
- 事物的隔离级别
- 读未提交
- 读已提交
- 可重复读
- 串行化
- 是否只读
- true(只读)
- false(可操作)
-
事物的传播行为:选择PROPAGATION_REQUIRED(支持当前事物,如果不存在就新建一个)即可。
-
Spring整合jdbc事物
dao实现类(继承JdbcDaoSupport类)
public class AccountUserDaoImpl extends JdbcDaoSupport implements AccountUserDao {
public void increase(Integer id,double money) {
String sql="update account set money=money+? where id=?";
//直接调用父类中的getJdbcTemplate方法得到jdbc模板对象,然后调用模板对象中的方法操作数据库
getJdbcTemplate().update(sql, money,id);
}
public void decrease(Integer id,double money) {
String sql="update account set money=money-? where id=?";
getJdbcTemplate().update(sql, money,id);
}
}
service实现类
public class AccountServiceImpl implements AccountService {
private AccountUserDao accountDao;
public void transfer(final Integer form, final Integer to, final double money) {
accountDao.decrease(form, money);
accountDao.increase(to, money);
}
public void setAccountDao(AccountUserDao accountDao) {
this.accountDao = accountDao;
}
}
xml配置文件
<!-- 指定db.properties文件的位置 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置连接池 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 事务管理核心对象 -->
<bean name="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean name="accountDao" class="cn.itcast.dao.AccountUserDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean name="accountService" class="cn.itcast.service.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!-- 配置通知 -->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<tx:method name="transfer" isolation="REPEATABLE_READ" read-only="false" propagation="REQUIRED" />
<!-- 如果想对所有方法进行增强则采用如下配置,但是注意:所有方法都必须遵循此命名规则 -->
<tx:method name="save*" isolation="REPEATABLE_READ" read-only="false" propagation="REQUIRED" />
<tx:method name="update*" isolation="REPEATABLE_READ" read-only="false" propagation="REQUIRED" />
<tx:method name="delete*" isolation="REPEATABLE_READ" read-only="false" propagation="REQUIRED" />
<tx:method name="get*" isolation="REPEATABLE_READ" read-only="true" propagation="REQUIRED" />
</tx:attributes>
</tx:advice>
<!-- 将通知织入到目标对象 -->
<aop:config>
<aop:pointcut
expression="execution(* cn.itcast.service.*ServiceImpl.transfer(..))"
id="txPc" />
<aop:advisor advice-ref="txAdvice" pointcut-ref="txPc" />
</aop:config>
使用注解配置jdbc事物:
xml文件
<!-- 指定db.properties文件的位置 -->
<context:property-placeholder location="classpath:db.properties" />
<!-- 配置连接池 -->
<bean name="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource">
<property name="jdbcUrl" value="${jdbc.jdbcUrl}"></property>
<property name="driverClass" value="${jdbc.driverClass}"></property>
<property name="user" value="${jdbc.user}"></property>
<property name="password" value="${jdbc.password}"></property>
</bean>
<!-- 事务管理核心对象 -->
<bean name="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean name="accountDao" class="cn.itcast.dao.AccountUserDaoImpl">
<property name="dataSource" ref="dataSource"></property>
</bean>
<bean name="accountService" class="cn.itcast.service.AccountServiceImpl">
<property name="accountDao" ref="accountDao"></property>
</bean>
<!-- 开启使用注解管理aop事物 -->
<tx:annotation-driven transaction-manager="transactionManager"/>
service实现类
//可以将注解配置到类上,对类中的所有方法都起作用,若类中某一方法的配置有所不同,可以在此方法上重写一个仅对此方法有用的配置
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED,readOnly=false)
public class AccountServiceImpl implements AccountService {
private AccountUserDao accountDao;
public void transfer(final Integer form, final Integer to, final double money) {
accountDao.decrease(form, money);
accountDao.increase(to, money);
}
@Transactional(isolation=Isolation.DEFAULT,propagation=Propagation.REQUIRED,readOnly=true)
public User get(int id){
User u=accountDao.get(id);
}
public void setAccountDao(AccountUserDao accountDao) {
this.accountDao = accountDao;
}
}