spring3

编程入门 行业动态 更新时间:2024-10-10 16:15:42

spring3

spring3

一:aop概念
即面向切面编程,通过预编译的方式和动态代理实现程序功能的统一维护的一种技术,是函数式编程的一种衍生泛型。通过对业务的各个部分进行隔离,从而使得业务逻辑各部分之间的耦合程度降低,提高程序的可重用性,提高了开发的效率。
二:作用:不修改源码的情况下进行增加。
三:实现方式:动态代理
四:使用切面编程:案例的问题:就是我们平时转账的时候,会有事务的提交,如果不成功就会通过事务的回滚而达到数据库不会进行改变。如果不用spring则会很麻烦。
代码如下:
4.1 结构

4.2.工具类,作用在注入sql语句的时候,关闭自动提交事务。

/*连接的工具类,它用于从数据源中获取一个连接,并实现和线程的绑定*/
public class connectionUtils {private ThreadLocal<Connection> t1=  new ThreadLocal<Connection>();private DataSource ds;public void setDs(DataSource ds) {this.ds = ds;}//获取当前线程上的连接public Connection getThreadConnection(){Connection connection = t1.get();//判断是否有连接if (connection==null){//从数据源中获取一个连接并且存入threadLocal中try {connection= ds.getConnection();t1.set(connection);} catch (SQLException throwables) {throwables.printStackTrace();}}return connection;}//把连接从线程上解绑public void removeThreadConnection(){t1.remove();}
}

4.2.2重新设置事务

public class transactionManager {private connectionUtils connectionUtil;public void setConnectionUtil(connectionUtils connectionUtil) {this.connectionUtil = connectionUtil;}public void beginTransaction(){//关闭自动提交try {connectionUtil.getThreadConnection().setAutoCommit(false);} catch (SQLException throwables) {throwables.printStackTrace();}}public void commit(){try {connectionUtil.getThreadConnection()mit();} catch (SQLException throwables) {throwables.printStackTrace();}}public void rollback(){try {connectionUtil.getThreadConnection().rollback();} catch (SQLException throwables) {throwables.printStackTrace();}}public void close(){try {connectionUtil.getThreadConnection().close();connectionUtil.removeThreadConnection();} catch (SQLException throwables) {throwables.printStackTrace();}}
}

4.3 数据库dao层

public class IaccountDaoImpl implements  IaccountDao{private QueryRunner runner;private connectionUtils connectionUtils;public void setConnectionUtils(utils.connectionUtils connectionUtils) {this.connectionUtils = connectionUtils;}public void setRunner(QueryRunner runner) {this.runner = runner;}public List<account> findAll() throws SQLException {return  runner.query(connectionUtils.getThreadConnection(),"select *from account",new BeanListHandler<account>(account.class));}public account findById(Integer id) throws SQLException {return runner.query(connectionUtils.getThreadConnection(),"select *from account where id=?",new BeanHandler<account>(account.class),id);}public void updateAcc(account acc) throws SQLException {runner.update(connectionUtils.getThreadConnection(),"update account set name=?,money=? where id=?",acc.getName(),acc.getMoney(),acc.getId());}public void deleteById(Integer id) throws SQLException {runner.update(connectionUtils.getThreadConnection(),"delete *from account where id =?",new BeanHandler<account>(account.class),id);}public void insert(account acc) throws SQLException {runner.update(connectionUtils.getThreadConnection(),"insert into account values(?,?)",acc.getName(),acc.getMoney());}public account findByNme(String name) throws SQLException {List<account> accounts= runner.query(connectionUtils.getThreadConnection(),"select *from account where name=?",new BeanListHandler<account>(account.class),name);if (accounts.size()==0||accounts==null){return null;}if (accounts.size()>1){throw new RuntimeException("结果集不唯一");}return accounts.get(0);}
}

4.4service层,可以清楚的感受到代码的冗余

@Component("accountService")
public class IaccountServiceImpl implements IaccountService
{private IaccountDao accDao;private transactionManager ts;public void setTs(transactionManager ts) {this.ts = ts;}public void setAccDao(IaccountDao accDao) {this.accDao = accDao;}//还有其他方法 ...省略实现了,跟下面一样public void insert(account acc) throws SQLException {try {//开启事务ts.beginTransaction();//执行操作accDao.insert(acc);//提交事务tsmit();//返回结果}catch (Exception E){//回滚ts.rollback();throw new RuntimeException(E);}finally {
//            释放ts.close();}}//模拟转账操作public void transfer(String sourceName , String targetName ,float money) throws SQLException {try {//开启事务ts.beginTransaction();//执行操作//获取转账人的钱数account aa = accDao.findByNme(sourceName);account bb = accDao.findByNme(targetName);//转账aa.setMoney(aa.getMoney()-money);bb.setMoney(bb.getMoney()+money);//更新accDao.updateAcc(aa);//int a=1/0;accDao.updateAcc(bb);//提交事务tsmit();//返回结果}catch (Exception E){//回滚ts.rollback();throw new RuntimeException(E);}finally {
//            释放ts.close();}}

4.5 bean.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=""xmlns:xsi=""xsi:schemaLocation="://www.springframework/schema/beans/spring-beans.xsd">
<!--配置dao--><!--配置service--><bean id="accountService" class="service.IaccountServiceImpl"><property name="accDao" ref="accountDao"/><property name="ts" ref="transactionManager"></property></bean><bean id="accountDao" class="dao.IaccountDaoImpl"><property name="runner" ref="runner1"/><property name="connectionUtils" ref="connectionUtils"></property></bean><!--事务管理--><bean id="transactionManager" class="utils.transactionManager"><property name="connectionUtil" ref="connectionUtils"></property></bean><bean id="connectionUtils" class="utils.connectionUtils"><property name="ds" ref="dataSource"></property></bean><!--  此处我们只注入了数据源,表明每条语句独立事务--><bean id="runner1" class="org.apachemons.dbutils.QueryRunner" scope="prototype"></bean><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property><property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/springOne?serverTimezone=UTC"></property><property name="user" value="root"></property><property name="password" value="admin"></property></bean>
</beans>

4.6 导入pom坐标

   <artifactId>spring-context</artifactId><artifactId>spring-test</artifactId><artifactId>c3p0</artifactId><artifactId>commons-dbutils</artifactId><artifactId>junit</artifactId><artifactId>mysql-connector-java</artifactId>

4.7 测试类

public class Spring_curd1 {@Testpublic void findAll() throws SQLException {ApplicationContext cc = new ClassPathXmlApplicationContext("bean.xml");IaccountService accountService = cc.getBean("accountService", IaccountService.class);accountService.transfer("aa","bb",100);}}

**由此可以明显的看出问题,业务层方法变得臃肿了,里面充斥着很多重复代码。并且业务层方法和事务控制方法耦合了。 试想一下,如果我们此时提交,回滚,释放资源中任何一个方法名变更,都需要修改业务层的代码。 **

五:更新后

学习 spring 中的 AOP 要明确的事 : a、开发阶段(我们做的) 编写核心业务代码(开发主线):大部分程序员来做,要求熟悉业务需求。 把公用代码抽取出来,制作成通知。(开发阶段最后再做):AOP 编程人员来做。 在配置文件中,声明切入点与通知间的关系,即切面。:AOP 编程人员来做。 b、运行阶段(Spring框架完成的) Spring 框架监控切入点方法的执行。一旦监控到切入点方法被运行,使用代理机制,动态创建目标对 象的代理对象,根据通知类别,在代理对象的对应位置,将通知对应的功能织入,完成完整的代码逻辑运行。

5.1 结构图

5.2
不变的是:
工具类在这里是connectionUtils和transactionManager不变
dao层不变
pojo层不变
自然测试类不变
变的是因为臃肿的service而导致的变化
service

@Component("accountService")
public class IaccountServiceImpl implements IaccountService
{private IaccountDao accDao;public void setAccDao(IaccountDao accDao) {this.accDao = accDao;}public List<account> findAll() throws SQLException {return accDao.findAll();}public account findById(Integer id) throws SQLException {return accDao.findById(id);}public void updateAcc(account acc) throws SQLException {accDao.updateAcc(acc);}public void deleteById(Integer id) throws SQLException {accDao.deleteById(id);}public void insert(account acc) throws SQLException {accDao.insert(acc);}public void transfer(String sourceName, String targetName, float money) throws SQLException {//执行操作//获取转账人的钱数account aa = accDao.findByNme(sourceName);account bb = accDao.findByNme(targetName);//转账aa.setMoney(aa.getMoney()-money);bb.setMoney(bb.getMoney()+money);//更新accDao.updateAcc(aa);
//    int a=1/0;accDao.updateAcc(bb);}
}

bean.xml

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns=""xmlns:xsi=""xmlns:aop=""xsi:schemaLocation="://www.springframework/schema/beans/spring-beans.xsd://www.springframework/schema/aop/spring-aop.xsd"><!--配置service--><bean id="accountService" class="lml.service.IaccountServiceImpl"><property name="accDao" ref="accountDao"></property></bean><!--配置dao--><bean id="accountDao" class="lml.dao.IaccountDaoImpl"><property name="runner" ref="runner1"></property><property name="connectionUtils" ref="connectionUtils"></property></bean><bean id="connectionUtils" class="config.connectionUtils"><property name="ds" ref="dataSource"></property></bean><bean id="tsmanager" class="config.transactionManager"><property name="connectionUtil" ref="connectionUtils"></property></bean><!-- 配置 runner此处我们只注入了数据源,表明每条语句独立事务--><bean id="runner1" class="org.apachemons.dbutils.QueryRunner" scope="prototype"><constructor-arg name="ds" ref="dataSource"></constructor-arg></bean><bean id="dataSource" class="com.mchange.v2.c3p0.ComboPooledDataSource"><property name="driverClass" value="com.mysql.cj.jdbc.Driver"></property><property name="jdbcUrl" value="jdbc:mysql://127.0.0.1:3306/springOne?serverTimezone=UTC"></property><property name="user" value="root"></property><property name="password" value="admin"></property></bean><!--配置切面编程--><aop:config><aop:aspect id="txAdvice" ref="tsmanager"><!--前置通知--><aop:before method="beginTransaction" pointcut-ref="pt"></aop:before><!--后置--><aop:after-returning method="commit" pointcut-ref="pt"></aop:after-returning><!--异常--><aop:after-throwing method="rollback" pointcut-ref="pt"></aop:after-throwing><!--最后--><aop:after method="close" pointcut-ref="pt"></aop:after><aop:pointcut id="pt" expression="execution(* lml.service.*.*(..))"/></aop:aspect></aop:config>
</beans>

pom.xml
在上面的基础上导入aop的包

  <artifactId>aopalliance</artifactId><artifactId>aspectjweaver</artifactId>

六:动态代理:字节码随用随创建,随用随加载。
理解:原本:a销售c。动态代理:a通过b代理,顺便b还送c礼品,流程 a-b-c;
1.基于接口(a)的增强
2.基于子类(b)的增强

1.1 基于接口(a)的增强
提供者:JDK 官方的 Proxy 类。
要求:被代理类最少实现一个接口

  创建的方式    Proxy.newProxyInstance(三个参数) * 参数含义:  ClassLoader:和被代理对象使用相同的类加载器。   Interfaces:和被代理对象具有相同的行为。实现相同的接口。InvocationHandler:如何代理。  Object one= Proxy.newProxyInstance(    a.getClass().getClassLoader(),   a.getClass().getInterfaces(),  new InvocationHandler() { //执行被代理对象的任何方法,都会经过该方法// proxy:代理对象的引用。不一定每次都用得到 //method:当前执行的方法对象 // args:执行方法所需的参数 @Override     public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {   增强...}

2.1基于子类(b)的增强
提供者:第三方的 CGLib,如果报 asmxxxx 异常,需要导入 asm.jar。
要求:被代理类不能用 final 修饰的类(最终类)。

 用到的类:  *   Enhancer *  用到的方法:*     create(Class, Callback) *  方法的参数:  *  *   Class:被代理对象的字节码 *   *   Callback:如何代理 
Object one= Enhancer.create(a.getClass(),new MethodInterceptor() {  /* 执行被代理对象的任何方法,都会经过该方法。在此方法内部就可以对被代理对象的任何 方法进行增强。    参数:前三个和基于接口的动态代理是一样的。MethodProxy:当前执行方法的代理对象。 */    @Override    public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methodProxy) throws Throwable { ...}

七:
Joinpoint(连接点): 所谓连接点是指那些被拦截到的点。在 spring 中,这些点指的是方法,因为 spring 只支持方法类型的 连接点。
Pointcut(切入点): 所谓切入点是指我们要对哪些 Joinpoint 进行拦截的定义。
Advice(通知/增强): 所谓通知是指拦截到 Joinpoint 之后所要做的事情就是通知。 通知的类型:前置通知,后置通知,异常通知,最终通知,环绕通知。
Introduction(引介): 引介是一种特殊的通知在不修改类代码的前提下, Introduction 可以在运行期为类动态地添加一些方 法或 Field。
Target(目标对象): 代理的目标对象。
Weaving(织入): 是指把增强应用到目标对象来创建新的代理对象的过程。 spring 采用动态代理织入,而 AspectJ 采用编译期织入和类装载期织入。
Proxy(代理): 一个类被 AOP 织入增强后,就产生一个结果代理类。 Aspect(切面): 是切入点和通知(引介)的结合。

更多推荐

spring3

本文发布于:2024-02-14 10:00:41,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1762771.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!