IoC 和 AOP 扩展

1.依赖注入扩展

.1.1构造注入

 Spring通过setter访问器实现对属性的赋值行为被称为“设值注入”。Spring通过构造方法赋值的能力,称为构造注入。
示例:
1.编写一个简单的类,添加有参和无参构造

/**
 * Desc:测试实体类
 * createBy:
 * Date: 2019/7/6 0006 0:02
 */
public class EntityUser {
    private String name;
    private String age;

    public EntityUser() {
    }
    public EntityUser(String name, String age) {
        this.name = name;
        this.age = age;
    }

    public void print(){
        System.out.println("姓名:"+"年龄是:"+age);
    }

 使用设值注入时,Spring通过JavaBean的无参构造方法实例化对象。当编写带参构造方法后,Java虚拟机不在提供默认的无参构造。为了保证使用的灵活性,最好添加一个无参构造。

2.在Spring的配置文件中将name属性和age属性以构造注入的方式赋值给EntityUser对象。代码如下:

  <bean id="entityUser" class="cn.kgc.Entity.EntityUser">
        <!--通过定义的有参构造为对象的属性name和age赋值-->
        <constructor-arg name="name" value="张三"/>
        <constructor-arg name="age" value="18"/>
    </bean>

经验:
1、一个<consturcotr-arg>元素表示构造方法的一个参数,且使用时不区分顺序,当构造方法的参数出现混淆、无法区分时,可以通过<consturcotr-arg>元素的index属性指定该参数的位置索引,索引从0开始。<consturcotr-arg>还提供了type属性用来指定参数的类型,避免字符串和基本数据类型的混淆。
2、构造注入的时效性好,在对象实例化时就得到所依赖的对象,便于在对象的初始化方法中使用依赖对象;但受于方法重载的形式,使用灵活性不足。设置注入使用灵活,但时效性不好。
3、Spring还提供了多种注入方式。

1.2 命名空间注入

 p 命名空间的特点是使用属性而不是子元素的形式来配置Bean的属性,从而简化Bean的配置。
使用p命名空间进行属性的注入需要添加P命名空间的声明。

直接量(基本数据类型、字符串)属性,使用方式如下:
语法 p:属性名 =“属性值”。

引用Bean的属性,使用方式如下:
语法 p:属性名-ref=“Bean的id”.
代码如下:

<?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:util="http://www.springframework.org/schema/util"
       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-4.0.xsd

        http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-4.0.xsd

        http://www.springframework.org/schema/util  http://www.springframework.org/schema/util/spring-util-4.0.xsd

        http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd

        http://www.springframework.org/schema/p  http://www.springframework.org/schema/p/spring-p-4.0.xsd">

    <!--通过p命名空间注入属性值-->
    <bean id="entityUser" class="cn.kgc.Entity.EntityUser"
    p:name="张三" p:age="18" p:hobby-ref="hobby">
    </bean>

1. 3.注入不同数据类型

 Spring提供了不同的标签来实现各种不同类型参数的注入,这些标签对于设值注入和构造注入都适用。

1.注入直接量(基本数据类型、字符串)
 对于 基本数据类型及其包装类、字符串,除了可以使用value属性,还可以通过<value>子元素进行注入,

 <!--通过value属性注入-->
    <bean id="entityUser" class="cn.kgc.Entity.EntityUser">
        <property name="name">
            <value>张三</value>
        </property>
        <property name="age">
            <value>18</value>
        </property>
    </bean>

如果属性中包含了xml中的特殊字符(&、<、>、"、’),则注入时需要进行处理。通常可以采用两种办法:

一、使用<![CDATA[]]>标记或把特殊字符替换为实体引用。
二、使用实体引用放肆
XML中的五个实体引用:

符号实体引用
<&lt ;
>&gt ;
&& amp;
,& apos;
"&quot ;

2、引用其他Bean组件

 Spring中定义的Bean可以互相引用,从而建立以来关系,除了使用ref属性,还可以通过<ref>子元素实现。示例如下:

<bean id="hobby" class="cn.kgc.Hobby"/>
<bean id="entityUser" class="cn.kgc.Entity.EntityUser">
        <property name="name">
         <ref bean="hobby"/>
        </property>
    </bean>

<ref>标签中的bean属性用来指定要引用的Bean的id。除了bean属性,在介绍一个local属性的用法。代码如下

 <bean id="hobby" class="cn.kgc.Hobby"/>
    <bean id="entityUser" class="cn.kgc.Entity.EntityUser">
            <property name="name">
             <ref local="hobby"/>
            </property>
        </bean>

local属性和bean属性都是用力啊指定要引用的Bean的id.他们的区别在于,Spring的配置文件是可以拆分成多个的,使用local属性只能在同一个配置文件中检索Bean的id,而使用bean属性可以在其他配置文件中检索id.
3.使用内部Bean
ruguo yige Bean组件尽在移除使用,可以把它定义为内部Bean。示例代码如下:

<bean id="entityUser" class="cn.kgc.Entity.EntityUser">
			 <bean class="cn.kgc.Hobby"/>
</bean>

4.注入集合类型的属性
(1).List 对于List或数组类型的属性,可以使用<List>标签注入。示例代码如下:

<bean id="entityUser" class="cn.kgc.Entity.EntityUser">
			<property name="hobbies">
			<list>
				<value>篮球</value>
				<value>乒乓球</value>
			</list>
				</property>
</bean>

(2).Set
对于Set类型的属性,可以使用标签注入。示例如下:

<bean id="entityUser" class="cn.kgc.Entity.EntityUser">
    			<property name="hobbies">
    				<set>
    					<value>篮球</value>
    					<value>乒乓球</value>
    				</set>
    			</property>
    </bean>

(3).Map
对于Map类型的属性,可以使用一下方式注入:

 <bean id="entityUser" class="cn.kgc.Entity.EntityUser">
        <property name="hobbies">
            <map>
                <entry>key<value>football</value></entry>
                <value>足球</value>
                <entry>key<value>basketball</value></entry>
                <value>篮球</value>
            </map>
        </property>
    </bean>

(4).Properties
对于Properties类型的属性,可以使用如下注入方式:

 <bean id="entityUser" class="cn.kgc.Entity.EntityUser">
        <property name="hobbies">
            <props>
                <prop key="football" >足球</prop>
                <prop key="basketBall">篮球</prop>
            </props>
        </property>
    </bean>

2 、其他增强类(异常抛出增强、最终增强、环绕增强)

2.1异常抛出增强:

 异常抛出增强的特点是在目标方法抛出异常是织入增强处理。使用异常抛出增强,可以为各功能模块提供同一个的、可以插拔的异常处理方案。
以下为异常抛出增强示例:

/**
 * Desc: 异常抛出增强类
 * createBy:
 * Date: 2019/7/6 0006 0:59
 */
public class ErrooLogger {
    
    private static final Logger log = Logger.getLogger(ErrooLogger.class);
    //增强方法
    public void afterThrowing(JoinPoint jp,RuntimeException e){
        log.error(jp.getSignature().getName()+"方法执行时发生异常:"+e);
    }
}

Spring.xml配置文件中的代码如下:

 <!--声明异常方法所在的Bean-->
    <bean id="theLogger" class="cn.kgc.util.ErrooLogger">
    </bean>
    <!--配置切面-->
    <aop:config>
        <!--定义切入点-->
        <aop:pointcut id="errorPointcut" expression="execution(* cn.kgc.service.*.*(..))"/>
        
        <!--引用包含增强方法的Bean-->
        <aop:aspect ref="theLogger">
            <!--将afterthrowing()方法定义为异常抛出增强并引用pointcut切入点-->
            <!--通过throwing属性指定为名为e的参数注入异常实例-->
            <aop:after-throwing method="afterThrowing" pointcut-ref="errorPointcut" throwing="e"/>
        </aop:aspect>
        
    </aop:config>

2.2实现最终增强

 最终增强的特点是无论方法抛出异常还是正常退出,该增强都会别执行,类似于异常处理机制中的finally块的作用,一般用于释放资源。使用最终增强,就可以为各个功能模块提供统一的、可插拔方案。
示例代码如下:

/**
 * Desc: 定义包含最终增强的Bean
 * createBy:
 * Date: 2019/7/6 0006 1:10
 */
public class AfterLogger {
    private static final Logger log = Logger.getLogger(AfterLogger.class);
    
    public void afterLogger(JoinPoint jp){
        log.info(jp.getSignature().getName()+"方法执行完毕!");
    }
    
}

Sprign配置文件中的代码:

<!--声明异常方法所在的Bean-->
    <bean id="afterLogger" class="cn.kgc.util.AfterLogger">
    </bean>
    <!--配置切面-->
    <aop:config>
        <!--定义切入点-->
        <aop:pointcut id="afterPointcut" expression="execution(* cn.kgc.service.*.*(..))"/>

        <!--引用包含增强方法的Bean-->
        <aop:aspect ref="afterLogger">
          <aop:after method="afterLogger" pointcut-ref="afterPointcut"/>
        </aop:aspect>

    </aop:config>

2.3实现环绕增强

 环绕增强是功能最强大的增强处理,Sprign把目标方法的控制权全都交给了它。环绕增强在目标方法的前后都可以植入增强处理。在环绕增强处理中,可以获取或修改目标方法的参数、返回值,可以对他进行异常处理,甚至可以决定目标方法是否被执行。
实现环绕增强代码如下:

**
 * Desc:定义环绕增强类
 * createBy:卢智伟
 * Date: 2019/7/6 0006 1:16
 */
public class AroundLogger {
    private static final Logger log = Logger.getLogger(AroundLogger.class);

    public Object aroundLogger(ProceedingJoinPoint jp) throws Throwable {

        log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法入参是:" + Arrays.toString(jp.getArgs()));

        try {
            Object result = jp.proceed(); //执行目标方法并获得返回值
            log.info("调用" + jp.getTarget() + "的" + jp.getSignature().getName() + "方法。方法返回值是:" + result);
            return result;
        } catch (Throwable e) {
            log.error(jp.getSignature().getName() + "方法执行时发生异常:" + e);
            throw e;
        }
    }

}
 <!--声明环绕增强方法所在的Bean-->
    <bean id="aroundLogger" class="cn.kgc.util.AroundLogger">
    </bean>
    <!--配置切面-->
    <aop:config>
        <!--定义切入点-->
        <aop:pointcut id="afterPointcut" expression="execution(* cn.kgc.service.*.*(..))"/>

        <!--引用包含增强方法的Bean-->
        <aop:aspect ref="aroundLogger">
          <!--将aroundLogger()方法定义为环绕增强并引用pointcut切入点-->
            <aop:around method="aroundLogger" pointcut-ref="afterPointcut"/>
            
        </aop:aspect>

    </aop:config>

 使用<aop:around>元素可以定义环绕增强。通过为增强方法声明ProceedingJoinPoint类型的参数,可以获得连接点信息,所用方法与JoinPoint相同。ProceedignJoinPoint是JoinPoint的子接口,其不但封装了目标方法及其入参数组,还封装了呗代理的目标对象,通过它的proceed()方法可以调用真正的目标方法,从而达到对连接点的完全控制。

总结:增强的类型

增强类型描述
前置增强方法执行前增加处理方法
后置增强方法执行后插入增强处理
异常抛出增强方法发生异常时插入增强处理
最终增强不管方法的执行状态如何都会插入增强处理
环绕增强在方法的各个方面都插入增强,是最强大的增强处理方案

3、使用注解实现IoC

3.1注解定义Bean组件

 Springcong 2.0版本开始引入注解的配置方式,将Bean的配置信息和Bean实现类结合在一起,进一步减少了配置文件的代码量。
 我们可以在JavaBean中通过注解实现Bean组件的定义。其配置方式如下:

 /**
 * Desc: 用户操作接口
 * createBy:卢智伟
 * Date: 2019/6/30 0030 16:58
 */
@Component("userDao")
public interface UserDao {

    public int addUser_UserDao(User user);

}

上述代码通过注解定义了一个名为userDao的Bean。
@Componet(“userDao”)的作用与在XML配置文件中编写<bean id = “userDao” class=“cn.kgc.dao.UserDaoImpl”/>等效。

此外还有三种特殊的注解:

注解用途
@Repository用于标注Dao类
@Service用于标注业务类
@Contoroller用于标注控制器类

 使用特定的注解可以使组件的用途更加清晰,并且Spring在以后的版本中可能回为他们添加特殊的功能,所以推荐使用特定的注解来标注特定的实现类。

3.2 注解装配Bean组件

 Spring提供了@Autowried注解来实现Bean的装配。
示例代码如下:

@Service("userService")
public class UserServiceImpl implements UserService {
    /**
     * 定义注解装载配件
     */

    @Autowired
    private UserDaoImpl userDao;

    /**
     * 使用@Resource注解来实现组件的装配
     */
    @Resource(name="userDao")
    private UserDao userDao2;

    public void setUserDao2(UserDao userDao2) {
        this.userDao2 = userDao2;
    }

 以上代码通过@Service标注了一个业务Bean,并使用@Autowired为dao属性注入所依赖的对象,spring将注解对dao属性进行复制,此时类中可以省略属性相关的setter方法。
 @Autowired采用按类型匹配的方式为属性自动装配合适的依赖对象,即容器会查找和属性类型相匹配的Bean组件,并自动为属性注入。若容器中有一个以上类型匹配的Bean是,则可以使用@Qualifier指定所需的Bean名称。
@Service(“userServiceImpl”)
public class UserServiceImpl implements UserService {

 /**
     * 定义注解转载配件
     */

    @Autowired
    @Qualifier("userDao")
    private UserDaoImpl userDao;

    /**
     * 使用@Resource注解来实现组件的装配
     */
    @Resource(name="userDao")
    private UserDao userDao2;

    public void setUserDao2(UserDao userDao2) {
        this.userDao2 = userDao2;
    }

3.3 加载注解定义的Bean组件

 使用注解定义完Bean组件,接下来就可以使用注解的配置信息启动Spring容器。
如何启动Spring容器:首先在Spring配置文件中添加对context命名空间的声明,然后使用<context:componet-scan>标签扫毛注解标注的类。base-package属性指定需要扫描的基准包(多个包名间用逗号隔开)。Spring会扫描这些包中的所有类,获取Bean的定义信息。
示例代码如下;

<?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"
       xmlns:aop="http://www.springframework.org/schema/aop" 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-4.0.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">
    <!--编写配置文件,使用注解配置信息启动spring容器-->
    <!--context 命名空间-component-scan命名空间的属性,base-package指定需要扫描的包,多个包用逗号隔开-->
    <context:component-scan base-package="com.kgc.dao,com.kgc.service"/>
</beans>

 补充:
 1、@Autowired也可以对方法的入参进行标注。也可用户构造方法,实现构造注入。不过这样的用法一般比较少,这里就不做详解了。
 2、使用@Autowired注解进行装配是,如果找不到相匹配的Bean组件,Spring容器就会抛出异常。此时如果依赖不是必需的,为避免抛出异常可以将required属性设置为false。如下所示:

 @Autowired(required = false);
    private UserDao userDao;

 需要注意的是required属性默认为true,即必须找到匹配的Bean完成装配,否则抛出异常。
 3、如果对类中集合类型的成员变量或方法入参使用@Autowired注解,Spring会将容器中所有和集合中元素类型匹配的Bean组件都注入进来。

3.4 使用@Resource注解实现组件装配

 除了提供@Autowired注解,Spring还支持使用JSR-250(JSR全称是:Java Specification Requests,Java规范提案)中定义的@Resource注解实现组件装配,该注解也能对类的成员变量或方法入参提供注入功能。
 @Resource有一个name属性,默认情况下,Spring将这个属性的值解释为要注入的Bean的名称,用法示例如下:

//为dao属性注入名为userDao的Bean
public class UserDaoImpl02 implements UserDao {
 
    //为dao属性注入名为userDao的Bean
    @Resource(name="userDao");
 
    private UserDao userDao;
    }

 如果没有显示的指定Bean的名称,@Resource注解将根据字段名或者setter方法名产生默认的名称:如果注解应用于字段,将使用字段名作为Bean的名称;如果注解应用于setter方法,Bean的名称就是通过setter方法得到的属性名。
 如果没有显示地指定Bean的名称,且无法找到与默认Bean名称相匹配的Bean组件,@Resource注解会有案名称查找的方式自动变为案类型匹配的方式进行装配。

4 使用注解实现AOP

4.1 认识AspectJ

 AspectJ是一个面向切面的框架,它扩展了Java语言、定义了AOP语法,能够在编译期提供代码的织人,它提供了一个专门的编译器用来生成遵守字节码规范的Class文件。

 Spring通过集成AspectJ实现了以注解的方式定义切面,大大减轻了配置文件的工作量。此外,因为Java的反射机制无法获取方法参数名,Spring还需要利用轻量的字节码处理框架asm(已经集成在Spring Core模块中)处理@AspectJ中所描述的方法参数名。

4.2 使用注解简化切面的配置

 使用注解前需要引入相应的命名空间aop,Spring配置文件引入该命名空间的代码如下:

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

        http://www.springframework.org/schema/aop  http://www.springframework.org/schema/aop/spring-aop-4.0.xsd

        http://www.springframework.org/schema/util  http://www.springframework.org/schema/util/spring-util-4.0.xsd

        http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd

        http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-4.0.xsd

        http://www.springframework.org/schema/p  http://www.springframework.org/schema/p/spring-p-4.0.xsd">
  
</beans>

接下来使用注解定义切面,以及插入相应的增强处理:

@Aspect
public class Logger_all {
    private Logger logger = Logger.getLogger(Logger_all.class);

    //定义前置增强方法
    @Before("execution(* main.java.cn.kgc.dao.impl.*.*(..))")
    public void before(JoinPoint jp){
       logger.info(("调用:"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法,方法的入参是:"+ Arrays.toString(jp.getArgs())));
    }

    //定义后置增强方法
    @AfterReturning(pointcut = "execution(* main.java.cn.kgc.dao.impl.*.*(..)",
    returning = "result")
    public void after(JoinPoint jp,Object result){
       logger.info(jp.getTarget()+"类的"+jp.getSignature().getName()+"方法执行完毕,方法的返回值是:"+result);
    }
}

以上各注解的作用:

注解用途
@Aspect定义切面
@Before定义前置增强方法
@After-Returning定义后置增强方法

 下面对这些注解做一些详细的解释:
 在上述示例中,使用@Aspect注解将UserServiceLogger定义为切面,并且使用@Before注解将before()方法定义为前置增强,使用@AfterRetuning注解将after()方法定义为后置增强。为了能够获取当前连接点的信息,在增强方法中添加了JoinPoint类型的参数,Spring会自动注入该实例。对于后置增强,还可以定义一个个参数用于接收该参数的名称,Spring会自动注入该实例。对于后置增强,还可以定义一个参数用于接收目标方法的返回值。需要注意的是,必须在@AfterRunting注解中通过returning属性指定该参数的名称,Spring会将目标方法的返回值赋值给指定名称的参数。

 而对于相同的切入点要求,可以统一定义,以便于重用和维护。
如下所示:

@Aspect
public class Logger_all {
    private Logger logger = Logger.getLogger(Logger_all.class);
	@Pointcut("execution(* main.java.cn.kgc.dao.impl.*.*(..))")    
	public void pointcut(){}
	
    //定义前置增强方法
    @Before("pointcut()")
    public void before(JoinPoint jp){
       logger.info(("调用:"+jp.getTarget()+"的"+jp.getSignature().getName()+"方法,方法的入参是:"+ Arrays.toString(jp.getArgs())));
    }

    //定义后置增强方法
    @AfterReturning(pointcut="pointcut()",
    returning = "result")
    public void after(JoinPoint jp,Object result){
       logger.info(jp.getTarget()+"类的"+jp.getSignature().getName()+"方法执行完毕,方法的返回值是:"+result);
    }
}

 切入点表达式使用@Pointcut注解来标识,而切入点签名则需通过一个普通的方法定义来提供,如上述示例中的pointcut()方法,作为切入点签名的方法必须返回void类型,定义好切入点以后,就可以使用"pointcut()"签名进行引用。
 切面定义完后,还需要在Spring配置文件中完成织如工作。配置代码如下:

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

    http://www.springframework.org/schema/util  http://www.springframework.org/schema/util/spring-util-4.0.xsd

    http://www.springframework.org/schema/context  http://www.springframework.org/schema/context/spring-context-4.0.xsd

    http://www.springframework.org/schema/tx  http://www.springframework.org/schema/tx/spring-tx-4.0.xsd

    http://www.springframework.org/schema/p  http://www.springframework.org/schema/p/spring-p-4.0.xsd">


    <!--扫描基准包中的注解-->
    <context:component-scan base-package="main.java.cn.kgc"/>
  
    <!--声明含有增强方法的Java Bean ,此处因为不需要被其他Bean引用所以不用指定id属性-->
    <bean class="main.java.cn.kgc.util.Logger_all"/>
   
    <!--启动切面的自动代理-->
    <aop:aspectj-autoproxy/>

 配置文件中<aop:aspectj-zuotoproxy>标签的作用:启动对于@AspectJ注解的支持,Spring将自动为匹配的Bean创建代理。

4.3 @AfterThrowing、@After和@Around注解的使用
 使用@AfterThrowing注解可以定义异常抛出增强。如果需要获取抛出的异常,可以为增强方法声明相关类型的参数,并通过@AfterThrowing的Throwing属性指定该参数名称,Spring会为其注入从目标方法抛出的异常实例。
示例如下:

@Aspect
public class ErrorLogger {
    Logger log = Logger.getLogger(ErrorLogger.class);

    //定义异常处理方法
    @AfterThrowing(pointcut = "execution(* main.java.cn.kgc.service.*.*(..))",throwing="e")
    public void afterThorwing(JoinPoint jp,RuntimeException e){
        log.info("执行:"+jp.getTarget()+"的:"+jp.getSignature().getName()+"时发生:"+e+"异常");
    }
}

 使用@After注解可以实现最终增强:

@Aspect
public class AfterLogger {
    Logger logger = Logger.getLogger(AfterLogger.class);
    @After("execution(* main.java.cn.kgc.service.*.*(..))")
    public void afterLogger(JoinPoint jp){
        logger.info(jp.getTarget()+"类的:"+jp.getSignature().getName()+"方法执行结束。");
    }
}

… 使用@Around注解可以定义环绕增强。通过为增强方法声明ProceedingJoinPoint类型的参数,可以获得连接点信息。通过它的proceed()方法可以条用真正的目标方法,从而实现对连接点的完全控制。示例如下:

/**
 * @description: 通过注解实现环绕增强
 * @author: 
 * @date: 2019-07-05 11:12
 */
@Aspect
public class AroundLogger {
    Logger logger = Logger.getLogger(AfterLogger.class);
    
    @Around("execution(* main.java.cn.kgc.*.*(..))")
    public Object aroundLogger(ProceedingJoinPoint pjp) throws Throwable {
        //前置增强
        logger.info("调用"+pjp.getTarget()+"的"+pjp.getSignature().getName()+"方法,方法入参是:"+ Arrays.toString(pjp.getArgs()));
        //异常处理增强
        try{
          Object result =  pjp.proceed(); //执行目标的方法
            logger.info("执行"+pjp.getTarget()+"的"+pjp.getSignature().getName()+"方法,方法入参是:"+ Arrays.toString(pjp.getArgs())+"方法的返回值是:"+result);

            //将执行的返回值返回
            return result;
        } catch(RuntimeException e){
            logger.error(pjp.getTarget()+"的"+pjp.getSignature().getName()+"方法执行时发生异常:"+e);
         throw e;
        } finally {
            //最终增强
            logger.info(pjp.getTarget()+"的"+pjp.getSignature().getName()+"方法执行完毕。");
        }
    }
}

总结:
1、Spring 提供了设置注入、构造注入等依赖注入方式。
2、使用 p 命名空间可以简化属性注入的配置。
3、Spring 提供的增强处理类型包括前置增强、后置增强、异常抛出增强、环绕增强、最终增强等。
4、通过Schema 形式将 POJO 的方法配置成切面,所用标签包括:

标签作用
<aop:aspect>定义切面
<aop:before>定义前置增强处理
<aop:after_returning>定义后置增强处理
<aop:around>定义环绕增强处理
<aop:after-throwing>定义异常抛出增强处理
<aop:after>定义最终增强处理。

5、用来定义Bean组件的注解包括:

注解用途
@Component用于定义普通类
@Repository用于标注Dao类
@Service用于标注业务类
@Contoroller用于标注控制器类

 使用特定的注解可以使组件的用途更加清晰,并且Spring在以后的版本中可能回为他们添加特殊的功能,所以推荐使用特定的注解来标注特定的实现类。
6、Bean组件的装配可以通过@Autowired、@Qualifier以及@Resource实现。
7、在Spring配置文件中使用<context:component-scan>元素扫描包含注解的类,来完成初始化。
8、使用注解方法定义切面可以简化配置公国,常用的注解有:

注解作用
@Aspect定义切面
@Before定义前置增强处理
@AfterRunting定义后置增强处理
@Around定义环绕增强处理
@AfterThrowing定义异常抛出增强处理
@After定义最终增强处理。

9、在配置文件中添加<aop:aspectj-autoproxy>元素,就可以启用对于@AspectJ注解的支持。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值