Spring中的IOC和AOP的使用,以及日志切面,数据库事务的案例

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的方式

  1. @Component
  2. @Controller
  3. @Service
  4. @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就可以了

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值