1.IOC
1.1基于xml开发
使用springIOC功能, 需要引入spring的context包
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-context</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
我通过把注释写在代码上, 来描述一下创建bean已经初始化bean的方法
<?xml version="1.0" encoding="UTF-8" ?>
<!-- beans里面引入spring的规范-->
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd">
<!-- 定义bean第一种方式(推荐使用) 直接通过id设置bean的名称,class指定bean的位置-->
<bean id="accountDao" class="com.sherlock.dao.impl.AccountDaoImpl"></bean>
<bean id="transferService" class="com.sherlock.service.impl.TransferServiceImpl">
<!-- 第一种通过给成员变量赋值的方式初始化
给transferService这个bean设置初始值 name为成员变量名称 ref表示引入当前文件中
另外一个id为accountDao的BEAN -->
<property name="AccountDao" ref="accountDao"></property>
<!--第二中方式,通过构造器的方式给成员变量赋初值
nane表示成员变量名称 value表示普通值-->
<constructor-arg name="age" value="12"></constructor-arg>
<constructor-arg name="cardNo" value="12323232sds"></constructor-arg>
<constructor-arg name="name" value="sherlock"></constructor-arg>
<!-- 下面是给复杂类型赋初值-->
<!-- set类型-->
<property name="mySet">
<set> <!-- 使用set标签包裹-->
<value>11</value> <!--value表示具体的值 -->
<value>22</value>
</set>
</property>
<!-- map类型-->
<property name="myMap">
<map><!-- 使用map标签包裹-->
<entry key="11" value="22"></entry> <!--entry 表示一对值 -->
<entry key="33" value="44"></entry>
</map>
</property>
<!-- list类型-->
<property name="myList">
<list><!-- 使用list标签包裹-->
<value>11</value><!--value表示具体的值 -->
<value>22</value>
</list>
</property>
<!-- peoperties类型-->
<property name="myProperties">
<props><!-- 使用props标签包裹-->
<prop key="prop1">11</prop><!--prop表示具体的值 -->
<prop key="prop2">22</prop>
</props>
</property>
<!--注意,set类型和list类型,里面的标签是可以互换的, 但是实际开发中不建议这样子 -->
</bean>
<!-- 第二种创建Bean的方式, 通过静态方法来创建 (自己new对象时使用)-->
<!-- 下面的意思为 定义一个id为factoryBean的bean, class表示类路径,
factory-method表示class这个类下一个静态方法, 而这个静态返回创建返回一个对象 -->
<bean id="factoryBean" class="com.sherlock.factory.CreateBeanFactory" factory-method="getFactoryBean"></bean>
<!-- 第三种创建Bean的方式, 通过实例化方法来创建 (自己new对象时使用)-->
<!-- 下面的意思为 定义一个id为createBeanFactory的bean, class表示类路径,
然后再创建一个id为testBean的bean, 这个bean的创建方式通过factory-bean指定工厂bean中的
factory-method方法来创建-->
<bean id="createBeanFactory" class="com.sherlock.factory.CreateBeanFactory"></bean>
<bean id="testBean" factory-bean="createBeanFactory" factory-method="getTestBean"></bean>
<!-- 使用lazy-init参数设为ture可以开启延迟加载, 即在使用这个bean时, 再去创建这个对象-->
<!-- scope有两辆种值可以选,singleton(默认值)单例模式,spring创建之后, 会管理
prototype多列模式, spring只负责创建, 不负责管理-->
<bean id="Account" lazy-init="true" scope="singleton"></bean>
</beans>
下面贴一下对应的一些bean代码
TransferServiceImpl.java
public class TransferServiceImpl implements TransferService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
private String name;
private String cardNo;
private Integer age;
public TransferServiceImpl(String name, String cardNo, Integer age) {
this.name = name;
this.cardNo = cardNo;
this.age = age;
}
private Set<String> mySet;
private List<String> myList;
private Map<String, String> myMap;
private Properties myProperties;
public void setMySet(Set<String> mySet) {
this.mySet = mySet;
}
public void setMyList(List<String> myList) {
this.myList = myList;
}
public void setMyMap(Map<String, String> myMap) {
this.myMap = myMap;
}
public void setMyProperties(Properties myProperties) {
this.myProperties = myProperties;
}
}
CreateBeanFactory.java
public class CreateBeanFactory {
public static FactoryBean getFactoryBean(){
return new FactoryBean(); // 对应就是一个普通的pojo
}
public TestBean getTestBean() {
return new TestBean(); // 对应就是一个普通的pojo
}
}
}
1.2基于xml和注解开发
xml和注解一起使用开发,我们定义bean可以使用注解来定义, 然后在xml中配置包扫码路径
四种定义bean的方式
- @Component
- @Controller
- @Service
- @Repository
上面四种方式都是在创建bean, 后面三种内部都是引用了@Component ,分这么多种出来主要是为了,让业务更加细分。
使用@Autowired来实现属性自动注入
下面我们来看一下具体的代码实现
<?xml version="1.0" encoding="UTF-8" ?>
<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
https://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/context https://www.springframework.org/schema/context/spring-context.xsd">
<!-- 配置扫描com.sherlock包下的所有文件-->
<context:component-scan base-package="com.sherlock"></context:component-scan>
</beans>
// 创建一个bean, 取名为transferService
@Service("transferService")
public class TransferServiceImpl implements TransferService {
@Autowired // 自动注入accountDao对象
private AccountDao accountDao;
}
//创建一个bean, 取名为accountDao
@Repository("accountDao")
public class AccountDaoImpl implements AccountDao {
@Autowired
private ConnectionUtils connectionUtils;
}
//创建一个bean, 取名为connectionUtils
@Component("connectionUtils")
public class ConnectionUtils {
}
1.3基于注解开发
纯基于注解开发与1.2讲的, 唯一的区别就是把xml消除, 上一节中xml只配置了包扫描,那么我们现在可以把包扫描的操作也配置在java类上, 如下面代码所示:
@Configuration // 表示这是一个配置类
@ComponentScan({"com.sherlock"}) // 扫描com.sherlock下的所有文件
public class SpringConfig {
}
2.AOP
我们以经典的日志切面为例, 来讲解一下aop的配置
2.1 基于xml
首先aop有一个切入点, 和5种通知类型。 其中切入点表示,这个aop逻辑需求对哪些功能点进去切入。通知类型为在具体的功能点执行前后,都会有想对应的方法进行通知,分别为,方法执行前,方法执行之后,方法正常执行完成之后,异常通知,环绕通知。下面我们通过代码来具体看一下怎么配置
public class LogUtils {
public void logPointCut() {
System.out.println("切入点...");
}
public void after() {
System.out.println("方法执行之后...");
}
public void before() {
System.out.println("方法执行之前...");
}
public void afterReturning(Object res) {
System.out.println("方法正常执行完成之后...");
}
public void afterThrowing(Throwable ex) {
System.out.println("异常通知");
}
public Object around (ProceedingJoinPoint point) throws Throwable {
Object result;
result = point.proceed();
return result;
}
}
<bean id="logUtils" class="com.sherlock.utils.LogUtils"></bean>
<aop:config>
<aop:aspect id="logAspect" ref="logUtils">
<!-- 使用aspectj语法表达式-->
<aop:pointcut id="pt1" expression="execution(* com.sherlock.service.impl.TransferServiceImpl.*(..))"/>
<!--方法执行之前 -->
<aop:before method="before" pointcut-ref="pt1"/>
<!--方法执行之后 -->
<aop:after method="after" pointcut-ref="pt1"/>
<!--方法正常逻辑执行之后 -->
<aop:after-returning method="afterReturning" returning="res" pointcut-ref="pt1"/>
<!-- 异常通知-->
<aop:after-throwing method="afterThrowing" pointcut-ref="pt1" throwing="ex"></aop:after-throwing>
<!--方法环绕在方法执行前后 -->
<aop:around method="around" pointcut-ref="pt1"/>
</aop:aspect>
</aop:config>
2.2 xml加注解
相对于纯xml需要把对应的切点,五种配置在xml中而言, xml加注解这个方式, 就只需要在xml中配置开启spring对aopectj的支持了, 然后在aop类上加上对应的注解即可
<aop:scoped-proxy ></aop:scoped-proxy>
@Component
@Aspect
public class LogUtils {
@Pointcut("execution(* com.sherlock.service.impl.TransferServiceImpl.*(..))")
public void logPointCut() {
System.out.println("切入点...");
}
@After("logPointCut()")
public void after() {
System.out.println("方法执行之后...");
}
@Before("logPointCut()")
public void before() {
System.out.println("方法执行之前...");
}
@AfterReturning("logPointCut()")
public void afterReturning(Object res) {
System.out.println("方法正常执行完成之后...");
}
@AfterThrowing("logPointCut()")
public void afterThrowing(Throwable ex) {
System.out.println("异常通知");
}
@Around("logPointCut()")
public Object around (ProceedingJoinPoint point) throws Throwable {
Object result;
result = point.proceed();
return result;
}
}
2.3基于注解
相对于第2种而言, 这种就只需要把xml中开启对aopaspect的支持换成在java类上配置注解就可以了, 所以说,我们只需要在配置类上加上@EnableAspectJAutoProxy这个注解即可
3.AOP与事物的结合
使用spring的aop功能, 需要引入spring的aop包,这里我们以事物为例, 所以我们也引入了关于事物的包
<!--spring aop的jar包支持-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aop</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<!--第三方的aop框架aspectj的jar-->
<dependency>
<groupId>org.aspectj</groupId>
<artifactId>aspectjweaver</artifactId>
<version>1.8.13</version>
</dependency>
<!--引入spring声明式事务相关-->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-tx</artifactId>
<version>5.1.12.RELEASE</version>
</dependency>
3.1基于xml
<?xml version="1.0" encoding="UTF-8" ?>
<beans
xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:tx="http://www.springframework.org/schema/tx"
xmlns:context="http://www.springframework.org/schema/context"
xsi:schemaLocation="
http://www.springframework.org/schema/beans
https://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop
https://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/tx
https://www.springframework.org/schema/tx/spring-tx.xsd
http://www.springframework.org/schema/context
https://www.springframework.org/schema/context/spring-context.xsd
">
<!-- 定义测试事物的service层-->
<bean id="transferService" class="com.sherlock.service.impl.TransferServiceImpl">
<property name="AccountDao" ref="accountDao"></property>
</bean>
<!-- 定义操作数据库的dao层-->
<bean id="accountDao" class="com.sherlock.dao.impl.JdbcTemplateDapImpl">
<!-- 设置属性值jdbcTemplate-->
<property name="jdbcTemplate" ref="jdbcTemplate"></property>
</bean>
<!-- 引入外部资源文件, 其实就是连接数据需要的参数-->
<context:property-placeholder location="classpath:jdbc.properties"/>
<!-- 设置数据源-->
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<!-- 设置jdbcTemplate使用的数据源-->
<bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate">
<constructor-arg name="dataSource" ref="dataSource"/>
</bean>
<!-- 设置事物管理器-->
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg name="dataSource" ref="dataSource"/>
</bean>
<!-- 定义事物的增强 使用的事物管理器为id为transactionManager的bean-->
<tx:advice id="txAdvice" transaction-manager="transactionManager">
<tx:attributes>
<!-- 设置所有的方法,propagation设置事物的传播行为
,REQUIRED为,调用一个方法,如果当前没有事物, 就创建一个事物,
如果有, 则加入到当前事物中 -->
<tx:method name="*" read-only="false" propagation="REQUIRED"/>
<!-- 设置方法名以query开头的所有方法,
SUPPORTS 如果当前有事物则加入事物,没有事物,则以非事物的方式执行 -->
<tx:method name="query*" read-only="true" propagation="SUPPORTS"/>
</tx:attributes>
</tx:advice>
<!-- 配置aop-->
<aop:config>
<!-- advice-ref指定增加方法为id为txAdvice, 切面为TransferServiceImpl这个类下的所有方法-->
<aop:advisor advice-ref="txAdvice"
pointcut="execution(* com.sherlock.service.impl.TransferServiceImpl.*(..))">
</aop:advisor>
</aop:config>
</beans>
public class TransferServiceImpl implements TransferService {
private AccountDao accountDao;
public void setAccountDao(AccountDao accountDao) {
this.accountDao = accountDao;
}
@Override
public void transfer(String fromCardNo, String toCardNo, int money) throws Exception {
Account from = this.accountDao.queryAccountByCardNo(fromCardNo);
Account to = this.accountDao.queryAccountByCardNo(toCardNo);
from.setMoney(from.getMoney()-money);
to.setMoney(to.getMoney()+money);
this.accountDao.updateAccountByCardNo(to);
//int i = 10/0;
this.accountDao.updateAccountByCardNo(from);
}
}
public class JdbcTemplateDapImpl implements AccountDao {
private JdbcTemplate jdbcTemplate;
public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
this.jdbcTemplate = jdbcTemplate;
}
@Override
public Account queryAccountByCardNo(String cardNo) throws Exception {
//具体的执行sql查询语句
String sql = "select * from account where cardNo=?";
return jdbcTemplate.queryForObject(sql, new RowMapper<Account>() {
@Override
public Account mapRow(ResultSet resultSet, int i) throws SQLException {
Account account = new Account();
account.setName(resultSet.getString("name"));
account.setCardNo(resultSet.getString("cardNo"));
account.setMoney(resultSet.getInt("money"));
return account;
}
}, cardNo);
}
@Override
public int updateAccountByCardNo(Account account) throws Exception {
//具体的执行sql更新语句
String sql = "update account set money=? where cardNo=?";
return jdbcTemplate.update(sql,account.getMoney(),account.getCardNo());
}
}
3.2基于xml和注解
在xml中,我们就只需要配置事物管理器, 和开启spring对注解事物的支持了, 就不需要在xml中配置aop的增强方法了
<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource">
<property name="driverClassName" value="${jdbc.driver}"></property>
<property name="url" value="${jdbc.url}"/>
<property name="username" value="${jdbc.username}"/>
<property name="password" value="${jdbc.password}"/>
</bean>
<bean id="transactionManager"
class="org.springframework.jdbc.datasource.DataSourceTransactionManager">
<constructor-arg name="dataSource" ref="dataSource"/>
</bean>
<tx:annotation-driven transaction-manager="transactionManager"></tx:annotation-driven>
然后再java类的方法(类)上, 直接加上 @Transactional就可以了
public class TransferServiceImpl implements TransferService {
@Transactional
@Override
public void transfer(String fromCardNo, String toCardNo, int money) throws Exception {
}
3.3基于注解
纯基于注解的方式就更简单了,我们只需要在配置类中,加上@EnableTransactionManagement,然后在对应的放上加上@Transactional就可以了