Spring中Ioc和AOP扩展

本文深入探讨Spring框架中的IoC(控制反转)和AOP(面向切面编程)核心概念,涵盖构造注入、p命名空间、不同数据类型注入、增强处理、注解实现IoC及AOP等内容。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Spring中Ioc和AOP扩展

1.构造注入

在HelloSpring案例中将HelloSpring类中的setter方法去掉,添加有参构造方法,编写带参构造方法后,Java虚拟机不再提供默认的无参构造方法,为了保证使用的灵活性,建议自行添加一个无参构造方法.

package cn.kgc.springdemo;

public class HelloSpring {
    private String who;

	// 通过构造方法设值注入
    public HelloSpring(){}
    public HelloSpring(String who) {
        this.who = who;
    }

    public void print(){
        System.out.println("Hello," + who +"!");
    }
	// 通过setter方法设值注入
    /*public String getWho() {
        return who;
    }
    public void setWho(String who) {
        this.who = who;
    }*/
}

同时将ApplicationContext.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"
       xsi:schemaLocation="http://www.springframework.org/schema/beans
        http://www.springframework.org/schema/beans/spring-beans.xsd http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd">

    <!-- bean元素声明spring创建的对象实例,id属性指定对象的唯一标识,方便程序的使用,class属性可以指定被声明的实例对应类j-->
    <bean id="helloSpring" class="cn.kgc.springdemo.HelloSpring">
        <!-- 设值注入-->
        <!--指定被复制的属性名-->
        <!--<property name="who">-->
            <!--&lt;!&ndash; 赋值内容 &ndash;&gt;-->
            <!--<value>SBX</value>-->
        <!--</property>-->

        <!-- 构造注入-->
        <constructor-arg>
            <value>SBX</value>
        </constructor-arg>
    </bean>
</beans>
1、一个<constructor-arg>元素表示构造方法的一个参数,且使用时不区分顺序。
2、通过<constructor-arg>元素的index 属性可以指定该参数的位置索引,位置从0 开始。
3、<constructor-arg>元素还提供了type 属性用来指定参数的类型,避免字符串和基本数
据类型的混淆。
构造注入与设值注入的优缺点
	与传统的JavaBean的写法更相似,程序开发人员更容易理解、接受。
通过setter方法设定依赖关系显得更加直观、自然。
	对于复杂的依赖关系,如果采用构造注入,会导致构造器过于臃肿,难以阅读。Spring在创建
Bean实例时,需要同时实例化其依赖的全部实例,因而导致性能下降。而使用设值注入,则能避免
这些问题。尤其是在某些属性可选的情况下,多参数的构造器更加笨重。

构造注入也不是绝对不如设值注入,在某些特定的场景下,构造注入比设值注入更优秀:

		构造注入可以在构造器中决定依赖关系的注入顺序,优先依赖的优先注入。例如,组件中
	其他依赖关系的注入,常常需要依赖于Datasource的注入。采用构造注入,可以在代码中清晰
	地决定注入顺序。

对于依赖关系无须变化的Bean,构造注入更有用处。因为没有setter方法,所有的依赖关系全部在构造器内设定。因此,无须担心后续的代码对依赖关系产生破坏。

依赖关系只能在构造器中设定,则只有组件的创建者才能改变组件的依赖关系。对组件的调用者而言,组件内部的依赖关系完全透明,更符合高内聚的原则。

综上所述,一般采用以设值注入为主,构造注入为辅的注入策略。对于依赖关系无须变化的的注入,尽量采用构造注入;而其他的依赖关系的注入,则考虑采用设值注入

2.使用p命名空间注入属性值

p 命名空间的特点:使用属性而不是子元素的形式配置Bean的属性,从而简化了配置代码.
对于直接量(基本数据类型、字符串)属性:p:属性名="属性值"
对于引用Bean的属性:p:属性名-ref="Bean的id"

使用前要先要在Spring配置文件中引入p命名空间

xmlns:p="http://www.springframework.org/schema/p"

使用p命名空间注入属性值

<bean id="user" class="entity.User" p:age="23" p:username="张三" 	
	p:email="zhangsan@xxx.com" />
<bean id="userService" class="service.impl.UserServiceImpl"
    p:dao-ref="userDao" />

使用p命名空间为业务Bean注入DAO对象

注入Bean类型的语法:p:属性名-ref="Bean的id

3.注入不同数据类型

首先创建一个TestEntity类来测试注入不同数据类型

package cn.kgc.entity;

import java.util.List;
import java.util.Map;
import java.util.Properties;
import java.util.Set;

public class TestEntity {
    private String specialCharacter1;   //
    private String specialCharacter2;
    private User innerBean;
    private List<String> list;
    private String[] array;
    private Set<String> set;
    private Map map;
    private Properties props;
    private String emptyValue;
    private String nullValue = "init value";

    public void setSpecialCharacter1(String specialCharacter1) {
        this.specialCharacter1 = specialCharacter1;
    }

    public void setSpecialCharacter2(String specialCharacter2) {
        this.specialCharacter2 = specialCharacter2;
    }

    public void setInnerBean(User innerBean) {
        this.innerBean = innerBean;
    }

    public void setList(List<String> list) {
        this.list = list;
    }

    public void setArray(String[] array) {
        this.array = array;
    }

    public void setSet(Set<String> set) {
        this.set = set;
    }

    public void setProps(Properties props) {
        this.props = props;
    }

    public void setEmptyValue(String emptyValue) {
        this.emptyValue = emptyValue;
    }

    public void setNullValue(String nullValue) {
        this.nullValue = nullValue;
    }

    public void showValue() {
        System.out.println("特殊字符1: " + this.specialCharacter1);
        System.out.println("内部Bean: " + this.innerBean.getUsername());
        System.out.println("List属性: " + this.list);
        System.out.println("数组属性[0]: " + this.array[0]);
        System.out.println("Set属性: " + this.set);
        System.out.println("Map属性: " + this.map);
        System.out.println("Properties属性: " + this.props);
        System.out.println("注入空字符串: " + this.emptyValue);
        System.out.println("注入null值: " + this.nullValue);
//       /* System.out.println("特殊字符2: " + this.specialCharacter2);
    }

    public void setMap(Map map) {
        this.map = map;
    }
}

其配置文件ApplicationContext.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: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/aop
        http://www.springframework.org/schema/aop/spring-aop.xsd">

    <bean id="testEntity" class="cn.kgc.entity.TestEntity">
        <!--不可用-->
         <!--使用CDATA处理xml中的特殊字符
        <property name="specialCharacter1">
            <value>![CDATA[P&G]]</value>
        </property>-->
        <!-- 配置特殊字符的值-->
        <property name="specialCharacter1">
            <value>P&amp;G</value>
        </property>
        <property name="innerBean">
            <bean class="cn.kgc.entity.User">
                <property name="username" value="徐辽"/>
                <property name="password" value="222"/>
            </bean>
        </property>
        <!--配置list集合类型的值-->
        <property name="list">
            <list>
                <value>足球</value>
                <value>蓝球</value>
            </list>
        </property>
        <!--配置数组类型的值-->
        <property name="array">
            <array>
                <value>足球</value>
                <value>蓝球</value>
            </array>
        </property>
        <!--配置set类型的值-->
        <property name="set">
            <set>
                <value>足球</value>
                <value>蓝球</value>
            </set>
        </property>
        <!--配置map类型的值-->
        <property name="map">
            <map>
                <entry>
                    <key><value>football</value></key>
                    <value>足球</value>
                </entry>
                <entry>
                    <key><value>basketball</value></key>
                    <value>篮球</value>
                </entry>
            </map>
        </property>
        <!--配置properties类型的值-->
        <property name="props">
            <props>
                <prop key="football">足球</prop>
                <prop key="basketball">篮球</prop>
            </props>
        </property>
        <!--赋值空字符串-->
        <property name="emptyValue"><value></value></property>
        <!--赋null值-->
        <property name="nullValue"><null/></property>
    </bean>
</beans>

4.增强处理

编写theLogger类运用增强处理实现日志的打印

package cn.kgc.aop;
import org.apache.log4j.Logger;
import org.aspectj.lang.JoinPoint;
import java.util.Arrays;

public class TheLogger {
    private static Logger log = Logger.getLogger(TheLogger.class);
    // 前置增强
    public void before(JoinPoint jp) {
        log.info("调用" + jp.getTarget() + "类的" + jp.getSignature().getName() +
                "方法, 方法参数:" + Arrays.toString(jp.getArgs()));
    }
    // 后置增强
    public void afterReturning(JoinPoint jp, Object result) {
        log.info("调用" + jp.getTarget() + "类的" + jp.getSignature().getName() +
                "方法, 方法返回值:" + result);
    }
    // 最终增强
    public void after(JoinPoint jp) {
        log.info(jp.getSignature().getName() + "方法结束了");
    }
    // 异常抛出增强
    public void afterThrowing(JoinPoint jp, Throwable e) {
        log.info(jp.getSignature().getName() + "方法出现了异常" + e);
    }
}

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

    <!-- bean元素声明spring创建的对象实例,id属性指定对象的唯一标识,方便程序的使用,class属性可以指定被声明的实例对应类j-->
    <bean id="helloSpring" class="cn.kgc.springdemo.HelloSpring">
        <!-- 设值注入-->
        <!--指定被复制的属性名-->
        <!--<property name="who">-->
            <!--&lt;!&ndash; 赋值内容 &ndash;&gt;-->
            <!--<value>SBX</value>-->
        <!--</property>-->

        <!-- 构造注入-->
        <constructor-arg>
            <value>SBX</value>
        </constructor-arg>
    </bean>

    <bean id="theLogger" class="cn.kgc.aop.TheLogger"/>

    <aop:config>
        <aop:pointcut id="pointcut" expression="execution(public void print())"/>
        <aop:aspect ref="theLogger">
            <aop:before method="before" pointcut-ref="pointcut"/>
            <aop:after-returning method="afterReturning" pointcut-ref="pointcut" returning="result"/>
            <aop:after-throwing method="afterThrowing" pointcut-ref="pointcut" throwing="e"/>
            <aop:after method="after" pointcut-ref="pointcut"/>
        </aop:aspect>
    </aop:config>
</beans>

常用增强处理类型
在这里插入图片描述
Spring AOP配置元素在这里插入图片描述

5.使用注解实现IoC

使用注解实现IoC

注解方式将Bean的定义信息和Bean实现类结合在一起,Spring提供的注解有
@Component:实现Bean组件的定义
@Repository :用于标注DAO类
@Service :用于标注业务类
@Controller :用于标注控制器类

/* @Repository("userDao")与在XML配置文件中编写
<bean id="userDao" 
class="dao.impl.UserDaoImpl" /> 
等效 */
@Repository("userDao") 
public class UserDaoImpl implements UserDao {}

使用@Autowired注解实现Bean的自动装配,默认按类型匹配,可以使用@Qualifier指定Bean的名称

// 可以对类的成员变量进行标注
@Service("userService") 
public class UserServiceImpl implements UserService { 
        @Autowired
        @Qualifier("userDao")
        private UserDao dao; 
               …… 
}
@Service("userService") 
public class UserServiceImpl implements UserService { 
        private UserDao dao;
        @Autowired // 也可以对方法的入参进行标注
        public void setDao((@Qualifier("userDao") UserDao dao) {
                 this.dao = dao;
        } 
  …… 
}

或者可以使用@Resource注解实现组件装配,默认按名称匹配

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

使用注解信息启动Spring容器,修改ApplicationContext.xml文件

<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/context
    http://www.springframework.org/schema/context/spring-context-3.2.xsd">
    <!-- 扫描包中注解标注的类 -->
    <context:component-scan base-package="service,dao" />
</beans>

6.使用注解定义切面

AspectJ

面向切面的框架,它扩展了Java语言,定义了AOP 语法,能够在编译期提供代码的织入

@AspectJ

AspectJ 5新增的功能,使用JDK 5.0 注解技术和正规的AspectJ切点表达式语言描述切面
Spring通过集成AspectJ实现了以注解的方式定义增强类,大大减少了配置文件中的工作量
利用轻量级的字节码处理框架asm处理@AspectJ中所描述的方法参数名
使用注解定义前置增强和后置增强实现日志功能
@Aspect
@Before 前置增强
@AfterReturning 后置增强
@AfterThrowing 异常抛出增强
@After 最终增强
@Around 环绕增强
编写Spring配置文件(ApplicationContext.xml),完成切面织入
<aop:aspectj-autoproxy />:启用对于@AspectJ注解的支持

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值