Spring框架深入学习总结

1. 增强类型扩展

(1) 异常抛出增强

异常抛出增强(Throws Advice)可以在方法抛出异常时执行特定的逻辑,例如日志记录或事务回滚。这种增强类型使得我们能够对异常进行统一处理,提升代码的可维护性和可读性。

package cn.ktjy.aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterThrowing;
import org.aspectj.lang.annotation.Aspect;



public class ErrorLogger {
    private static final Logger logger=Logger.getLogger(ErrorLogger.class);

    
    public void afterThrowing(JoinPoint jp,RuntimeException e){
        logger.error(jp.getSignature().getName()+"方法发生异常:"+e);
    }
}
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* service.UserService.*(..))"/>
        <aop:aspect ref="theLogger">
            <aop:after-throwing method="afterThrowing"
                                pointcut-ref="pointcut" throwing="e"/>
        </aop:aspect>
    </aop:config>

(2) 最终增强

最终增强(After Finally Advice)无论目标方法是否抛出异常,都会在方法执行后运行。这类增强通常用于资源的清理操作,如关闭文件流或数据库连接。

package cn.ktjy.aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.After;
import org.aspectj.lang.annotation.Aspect;


public class AfterLogger {
    private static final Logger logger=Logger.getLogger(AfterLogger.class);

   
    public void afterLogger(JoinPoint jp){
        logger.info(jp.getSignature().getName()+"方法结束执行。");
    }
}
    <bean id="theLogger" class="cn.ktjy.aop.AfterLogger"></bean>
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* service.UserService.*(..))"/>
        <aop:aspect ref="theLogger">
            <aop:after method="afterLogger" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

(3) 环绕增强

环绕增强(Around Advice)提供了在方法执行前后执行自定义逻辑的能力。这种增强类型最为灵活,可以在方法调用前后添加行为,甚至可以完全替代目标方法的执行。

package cn.ktjy.aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;

import java.util.Arrays;


public class AroundLogger {
    private static final Logger logger=Logger.getLogger(AroundLogger.class);

    public Object aroundLogger(ProceedingJoinPoint jp)throws Throwable{
        logger.info("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。方法入参:"+ Arrays.toString(jp.getArgs()));
        try {
            Object result=jp.proceed();
            logger.info("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。方法返回值:"+result);
            return result;
        } catch (Throwable e) {
            logger.error(jp.getSignature().getName()+"方法发生异常:"+e);
            throw e;
        } finally {
            logger.info(jp.getSignature().getName()+" 方法结束执行。 ");
        }
    }
}
    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(* .UserService.*(..))"/>
        <aop:aspect ref="theLogger">
            <aop:around method="aroundLogger" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>

2. 依赖注入方式扩展

(1) 构造注入

构造注入通过构造器为类注入依赖项。它确保了对象在创建时就已经具备所有必需的依赖,适用于强制依赖的场景。

package cn.ktjy.service.impl;

import cn.ktjy.dao.UserDao;
import cn.ktjy.dao.impl.UserDaoImpl;
import cn.ktjy.pojo.User;
import cn.ktjy.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

public class UserServiceImpl implements UserService {
//    //实例化所依赖的UserDao对象
//    private UserDao dao=new UserDaoImpl();
//
//    /**
//     * 保存用户信息
//     * @param user
//     */
//    public void save(User user) {
//        dao.save(user);
//    }

    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    private UserDao userDao;

    public int save(User user){
        return userDao.save(user);
    }
}
    <bean id="userDao" class="dao.impl.UserDaoImpl"></bean>
    <bean id="userService" class="service.impl.UserServiceImpl">
        <constructor-arg name="userDao" ref="userDao"/>
    </bean>

(3) p命名空间注入

p命名空间注入是一种简化的属性注入方式,使用XML配置文件中的p命名空间来注入属性,减少了配置文件的复杂度。

注意:在beans标签中加入xmlns:p="http://www.springframework.org/schema/p"否则无法使用p命名空间 

<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:context="http://www.springframework.org/schema/context"
       xmlns:p="http://www.springframework.org/schema/p"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/context
       http://www.springframework.org/schema/context/spring-context.xsd
       http://www.springframework.org/schema/aop
       http://www.springframework.org/schema/aop/spring-aop.xsd">

<bean id="LuFei" class="pojo.Speak" p:name="路飞" p:speak="我是要成为海贼王的男人!"/>
<bean id="KongMing" class="pojo.Speak" p:name="诸葛亮" p:speak="从未见过如此厚颜无耻之人!"/>

</beans>

(4) 不同数据类型的注入

Spring支持多种数据类型的注入,包括基本数据类型、集合类型、Map类型等。了解并熟练掌握这些注入方式,有助于我们在实际项目中灵活应用。

    <bean id="user" class="cn.ktjy.pojo.User">
        <property name="username">
            <value>诸葛亮</value>
        </property>
        <property name="age">
            <value>27</value>
        </property>
        <property name="evaluate">
            <value>鞠躬尽瘁,死而后已</value>
        </property>
    </bean>


    <bean id="entity" class="cn.ktjy.pojo.TestEntity">
        <property name="emptyValue">
            <value></value>
        </property>
        <property name="nullValue">
            <null/>
        </property>
    </bean>

    <bean id="entity" class="cn.ktjy.pojo.TestEntity">
        <property name="specialCharacter1">
            <value><![CDATA[诸葛亮&路飞]]></value>
        </property>
        <property name="specialCharacter2">
            <value>诸葛亮&amp;路飞</value>
        </property>
    </bean>

    <bean id="entity" class="cn.ktjy.pojo.TestEntity">
        <property name="list">
            <list>
                <value>青龙偃月刀</value>
                <value>丈八点钢矛</value>
            </list>
        </property>
    </bean>

    <bean id="entity" class="cn.ktjy.pojo.TestEntity">
        <property name="set">
            <set>
                <value>青龙偃月刀</value>
                <value>丈八点钢矛</value>
            </set>
        </property>
    </bean>

    <bean id="entity" class="cn.ktjy.pojo.TestEntity">
        <property name="map">
            <map>
                <entry>
                    <key><value>knife</value></key>
                    <value>青龙偃月刀</value>
                </entry>
                <entry>
                    <key><value>spear</value></key>
                    <value>丈八点钢矛</value>
                </entry>
            </map>
        </property>
    </bean>

    <bean id="entity" class="cn.ktjy.pojo.TestEntity">
        <property name="props">
           <props>
               <prop key="knife">青龙偃月刀</prop>
               <prop key="spear">丈八点钢矛</prop>
           </props>
        </property>
    </bean>

<bean id="user" class="cn.ktjy.pojo.User"/>
    <bean id="entity" class="cn.ktjy.pojo.TestEntity">
        <property name="outUser">
            <ref bean="user"/>
        </property>
    </bean>
    <bean id="entity" class="cn.ktjy.pojo.TestEntity">
        <property name="innerBean">
            <bean class="cn.ktjy.pojo.User"/>
        </property>
    </bean>

3. 使用注解方式完成Bean的装配

通过Spring的注解机制,可以简化配置和代码,使用注解如@Service@Component等标注业务类,使用@AutoWire、@Resource实现用户保存功能。

@Autowired

  1. 来源: @Autowired是Spring框架提供的注解。
  2. 自动注入: 默认情况下,@Autowired根据类型进行自动注入。它会在Spring容器中查找匹配类型的bean,并自动注入到标注的属性、构造器或方法中。
  3. 可选属性:required属性:默认为true,表示如果Spring容器中没有找到匹配的bean,会抛出异常。如果设置为false,则在没有匹配bean时,不会注入。
  4. 使用场景: 适用于需要按照类型进行注入的场景,特别是在Spring框架的上下文中使用频繁。

@Resource

  1. 来源: @Resource是Java标准的注解(由JSR-250规范定义),并由Spring支持。
  2. 名称优先: @Resource默认情况下根据名称进行注入。它首先会查找与属性名或指定名称匹配的bean。如果找不到匹配的名称,再根据类型查找。
  3. 属性:
    • name属性:指定要注入的bean的名称。如果没有指定name属性,则使用标注的属性名。
    • type属性:指定要注入的bean的类型。
  4. 使用场景: 适用于需要按照名称进行注入的场景,特别是在需要与Java EE兼容的环境中使用较多。
package cn.ktjy.dao.impl;

import cn.ktjy.dao.UserDao;
import cn.ktjy.pojo.User;
import org.springframework.stereotype.Component;

@Component("userDao")
public class UserDaoImpl implements UserDao {
//    //通过工厂获取所依赖的UserDao对象
//    private UserDao dao= UserDaoFactory.getInstance();

    /**
     * 保存用户信息
     * @param user
     */
    public int save(User user) {
        int count=1;
        System.out.println("保存用户到数据库");
//        throw new RuntimeException("测试异常");
        return count;
    }
}
package cn.ktjy.service.impl;

import cn.ktjy.dao.UserDao;
import cn.ktjy.dao.impl.UserDaoImpl;
import cn.ktjy.pojo.User;
import cn.ktjy.service.UserService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;

@Service("userService")
public class UserServiceImpl implements UserService {
//    //实例化所依赖的UserDao对象
//    private UserDao dao=new UserDaoImpl();
//
//    /**
//     * 保存用户信息
//     * @param user
//     */
//    public void save(User user) {
//        dao.save(user);
//    }

    public UserServiceImpl(UserDao userDao) {
        this.userDao = userDao;
    }

    @Autowired
    private UserDao userDao;

    public int save(User user){
        return userDao.save(user);
    }
}

4. 使用注解实现Spring AOP

(1) 使用注解方式标注切面

通过注解如@Aspect@Pointcut等,标注和定义切面,使AOP的实现更加简洁和直观。

package cn.ktjy.aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import java.util.Arrays;


@Aspect
public class UserServiceLogger {
    private static final Logger log=Logger.getLogger(UserServiceLogger.class);

    /**
     * 前置增强
     * @param jp
     */
  
    public void before(JoinPoint jp){
        log.info("调用 "+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。方法入参:"+ Arrays.toString(jp.getArgs()));
    }

    /**
     * 后置增强
     * @param jp
     * @param returnValue
     */
    
    public void afterReturning(JoinPoint jp,Object returnValue){
        log.info("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法,方法返回值:"+returnValue);
    }
}

(2) 使用注解定义其他类型的增强

使用注解如@Before@After@Around等,可以方便地定义各种类型的增强逻辑,满足不同的业务需求。

package cn.ktjy.aop;

import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.AfterReturning;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;

import java.util.Arrays;


@Aspect
public class UserServiceLogger {
    private static final Logger log=Logger.getLogger(UserServiceLogger.class);

    /**
     * 前置增强
     * @param jp
     */
    @Before("execution(* cn.ktjy.service.UserService.*(..))")
    public void before(JoinPoint jp){
        log.info("调用 "+jp.getTarget()+"的"+jp.getSignature().getName()+"方法。方法入参:"+ Arrays.toString(jp.getArgs()));
    }

    /**
     * 后置增强
     * @param jp
     * @param returnValue
     */
    @AfterReturning(pointcut = "execution(* cn.ktjy.service.UserService.*(..))",returning = "returnValue")
    public void afterReturning(JoinPoint jp,Object returnValue){
        log.info("调用"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法,方法返回值:"+returnValue);
    }
}

根据不同的应用场景选择合适的依赖注入(DI)和面向切面编程(AOP)方式,可以提高代码的可维护性、可扩展性和模块化程度。

  • 12
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值