3.Spring的IOC与AOP

Spring概述

Spring
  • 轻量级框架,应用于Java EE,当前主流框架
  • “一站式” 的企业应用开发框架
目标
  • 使现有技术更加易用,推进编码最佳实践
内容
  • IOC容器

  • AOP面向切片编程

  • 数据访问支持
    简化JDBC/ORM框架
    声明式事务

  • Web集成

控制反转IOC(依赖注入)

IOC容器将组件对象的控制权从代码本身转移到外部容器

组件化思想:分离关注的,使用接口,不在关注实现

目的:解耦合,实现每个组件时,只关注组件内部的事情

spring下载网址:https://repo.spring.io/webapp/#/home
在这里插入图片描述

使用Spring Ioc进行设值注入
/**
* Java类
*/
private class HelloSpring{
	private String who;
	/**
	* 打印方法
	*/
	public void print(){
		System.out.println("Hello,"+ this.getWho() + "!");
	}
	/**
	* 提供get/Set方法提供设值注入
	*/
	public String getWho() {
   		 return who;
	}

	public void setWho(String who) {
    	this.who = who;
	}
}
<!--创建ApplicationContext.xml-->
<?xml version="1.0" encoding="UTF-8" ?>   
<beans xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
 xmlns="http://www.springframework.org/schema/beans"  
 xsi:schemaLocation="http://www.springframework.org/schema/beans 
 http://www.springframework.org/schema/beans/spring-beans-3..xsd">   
<!--bean元素声明spring创建的对象实例-->
	<bean id = "helloSpring" class="HelloSpring">
		<!--对HelloSpring里who变量赋值为123-->
		<property name = "who" value="123"/>
	</bean>
	
</beans>

构造注入
<?xml version="1.0" encoding="UTF-8"?>
<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
	http://www.springframework.org/schema/beans/spring-beans-3.2.xsd ">
	<!-- 定义UserDaoImpl对象,并指定id为userDao -->
	<bean id="userDao" class="dao.impl.UserDaoImpl" />
	<!-- 定义UserServiceImpl对象,并指定id为userService -->
	<bean id="userService" class="service.impl.UserServiceImpl">
		<!-- 1.通过定义的单参构造为userService的dao属性赋值 -->
			<constructor-arg>
				<!-- 引用id为userDao的对象为userService的dao属性赋值 -->
				<ref bean="userDao" />
			</constructor-arg>
		<!--2.通过索引构造为userService的dao属性赋值 -->
			<constructor-arg index="1">
				<!-- 引用id为userDao的对象为userService的dao属性赋值 -->
				<value>123</value>
			</constructor-arg>
		<!--3.通过类型构造为userService的dao属性赋值 -->
			<constructor-arg type="int">
				<!-- 引用id为userDao的对象为userService的dao属性赋值 -->
				<value>123</value>
			</constructor-arg>
	</bean>
</beans>
p命名空间注入
/**
* 实体类
*/
public class User {
    private String  userName;
    private int age;
    private String email;
    //....省略get/set方法
}
<?xml version="1.0" encoding="UTF-8"?>
<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
	http://www.springframework.org/schema/beans/spring-beans-3.2.xsd ">
	<!--对实体类进行P命名空间注入属性-->
	<bean id="user" class="entity.User" p:username="张三" p:age="23"
	p:email="zhangsan@bdqn.com" />
	<bean id="userDao" class="dao.impl.UserDaoImpl" />
	<!--p:ref对引入的属性是对象属性类型-->
	<bean id="userService" class="service.impl.UserServiceImpl" p:dao-ref="userDao" />
</beans>
使用不同数据类型注入
<?xml version="1.0" encoding="UTF-8"?>
<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
	http://www.springframework.org/schema/beans/spring-beans-3.2.xsd">
	<bean id="entity" class="entity.TestEntity">
		<!-- 使用<![CDATA[]]>标记处理XML特 殊字符 -->
		<property name="specialCharacter1">
			<value><![CDATA[P&G]]></value>
		</property>
		<!-- 把XML特殊字符替换为实体引用 -->
		<property name="specialCharacter2">
			<value>P&amp;G</value>
		</property>
		<!-- 定义内部Bean -->
		<property name="innerBean">
			<bean class="entity.User">
				<property name="username">
					<value>Mr. Inner</value>
				</property>
			</bean>
		</property>
		<!-- 注入List类型 -->
		<property name="list">
			<list>
				<!-- 定义List中的元素 -->
				<value>足球</value>
				<value>篮球</value>
			</list>
		</property>
		<!-- 注入数组类型 -->
		<property name="array">
			<list>
				<!-- 定义数组中的元素 -->
				<value>足球</value>
				<value>篮球</value>
			</list>
		</property>
		<!-- 注入Set类型 -->
		<property name="set">
			<set>
				<!-- 定义Set或数组中的元素 -->
				<value>足球</value>
				<value>篮球</value>
			</set>
		</property>
		<!-- 注入Map类型 -->
		<property name="map">
			<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>
				<!-- 定义Properties中的键值对 -->
				<prop key="football">足球</prop>
				<prop key="basketball">篮球</prop>
			</props>
		</property>
		<!-- 注入空字符串值 -->
		<property name="emptyValue">
			<value></value>
		</property>
		<!-- 注入null值 -->
		<property name="nullValue">
			<null/>
		</property>
	</bean>
</beans>

切片编程AOP

AOP的目标
  1. 可以让我们专心做事

  2. 使用时需要在头文件加入需要使用的组件地址,头文件可以在帮助文档找相关

AOP原理
  1. 将复杂的需求分解出不同方面,将公共功能集中解决

  2. 采用代理机制组装起来运行,在不改变原程序的基础上对代码段进行增强处理,增加新的功能

  3. 所谓的面向切片编程,是一种通过预编译方式和运行期动态代理使现在不修改源代码的情况下 给程序动态添加功能的技术

  4. AOP相关术语

    Aspect(切面): Aspect 声明类似于 Java 中的类声明,在 Aspect 中会包含着一些 Pointcut 以及相应的 Advice。

    Joint point(连接点):表示在程序中明确定义的点,典型的包括方法调用,对类成员的访问以及异常处理程序块的执行等 等,它自身还可以嵌套其它 joint point。

    Pointcut(切点):表示一组 joint point,这些 joint point 或是通过逻辑关系组合起来,或是通过通配、正则表达式等方式集中起来,它定义了相应的 Advice 将要发生的地方。

    <!-- 配置切面 -->
    <aop:config>
    	<!-- 定义切入点 -->
    	<aop:pointcut id="pointcut" expression="execution(* service.UserService.*(..))" />
    	
    </aop:config>
    

    Advice(增强):Advice 定义了在 Pointcut 里面定义的程序点具体要做的操作,它通过 before、after 和 around 来区别是在每个 joint point 之前、之后还是代替执行的代码。

    编写增强类	
    public class UserServiceLogger{
    	private static Logger log = Logger.getLogger(UserServiceLogger.class);
    	public void before(JoinPoint jp){
    		log.info("调用"+jp.getTarget()+"的"+
    			jp.getSignature().getName()+"方法.方法入参:"+Arrays.toString(jp.getArgs()))
    	}
    	public void afterRetruning(JoinPoint jp){
    		log.info("调用"+jp.getTarget()+"的"+
    			jp.getSignature().getName()+"方法.方法返回值:"+result)
    	}
    }
    
    • 前置增强
    <bean id="dao" class="com.dao.impl.IUserDaoImpl"></bean>
    	<bean id="biz" class="com.biz.impl.IUserBizImpl">
        <!-- 要引用dao -->
        <property name="dao" ref="dao"></property>
    </bean>
    <bean id="logbefore" class="com.aop.before"></bean>
    <aop:config>
            <!-- 引用的是biz中的 -->
            <aop:pointcut expression="execution(public void save(com.domain.User))" id="pointcut"/>    
            <!-- 将增强处理和切入点结合在一起,在切入点处插入增强处理,完成“织入” -->
            <aop:advisor advice-ref="logbefore" pointcut-ref="pointcut"/>
            
    </aop:config>
    
    1. 后置增强
    <bean id="dao" class="com.dao.impl.IUserDaoImpl"></bean>
    	<bean id="biz" class="com.biz.impl.IUserBizImpl">
        <!-- 要引用dao -->
        <property name="dao" ref="dao"></property>
    </bean>
    <bean id="after" class="com.aop.afterRetruning"></bean>
    <aop:config>
            <!-- 引用的是biz中的 -->
            <aop:pointcut expression="execution(public void save(com.domain.User))" id="pointcut"/>    
            <!-- 将增强处理和切入点结合在一起,在切入点处插入增强处理,完成“织入” -->
            <aop:advisor advice-ref="after" pointcut-ref="pointcut"/>
    </aop:config>
    
    1. 环绕增强、异常抛出增强、最终增强等类型
    /**
    *编写增强类和环绕增强方法
    *
    */
    public class AroundLogger {
    private static Logger logger = Logger.getLogger(AroundLogger.class);
    //环绕增强方法,集合了前增强和后增强和最终增强
    public Object aroundLooger(ProceedingJoinPoint j) throws Throwable {
    	//类似前置增强
        logger.info("调用" + j.getTarget() + "的" + j.getSignature() +
                "方法,方法参数:"+ Arrays.toString(j.getArgs()));
         //定义返回值
        Object result;
        try{
        	//类似后增强
            result = j.proceed();
            logger.info("调用" + j.getTarget() + "的" +j.getSignature()+
                    "方法,方法返回值:"+result);
            return result;
            
        }catch (Throwable e){
            //异常抛出增强
            logger.error(j.getSignature().getName() + "方法发生异常" +e);
            throw e;
            
        }finally {
            //最终增强
            logger.error(j.getSignature().getName()+"方法结束");
      	  }
       }
    }
    

    Target(目标对象):织入 Advice 的目标对象.。

    Weaving(织入):将 Aspect 和其他对象连接起来, 并创建 Adviced object 的过程,在切入点插入增强处理

    <?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-3.2.xsd
    	http://www.springframework.org/schema/aop
    	http://www.springframework.org/schema/aop/spring-aop-3.2.xsd">
    	<bean id="dao" class="dao.impl.UserDaoImpl"></bean>
    	<bean id="service" class="service.impl.UserServiceImpl">
    		<property name="dao" ref="dao"></property>
    	</bean>
    	<!-- 声明增强方法所在的Bean -->
    	<bean id="theLogger" class="aop.ErrorLogger"></bean>
    	<!-- 配置切面 -->
    	<aop:config>
    		<!-- 定义切入点 -->
    		<aop:pointcut id="pointcut" expression="execution(* service.UserService.*(..))" />
    		<!-- 增强处理对象 -->
    		<aop:aspect ref="userServiceLogger">
    			<!--前置增强,before为被织入的方法-->
    			<aop:before method="before"
    				pointcut-ref="pointcut"/>
    			<!--后置增强-->
    			<aop:after-throwing method="afterThrowing"
    				pointcut-ref="pointcut" returning="result" />
    		</aop:aspect>
    	</aop:config>
    </beans>
    

    表达式匹配规则
    在这里插入图片描述

使用注解实现IOC与AOP

IOC

注解方式讲Bean定义信息和Bean实现类结合在一起,Spring提供的注解有

@Component:实现Bean组件的定义

@ Repository:标注DAO类
//给userDao注解一个bean名称等价于<bean id="userDao" class="UserDaoImpl">
@Repository("userDao")
public class UserDaoImpl implements UserDao{
  	.....省略各种接口实现
}
@ Service:标注业务类
使用@Autowired注解实现Bean的自动装配,默认按类型匹配
@Autowired(required=false):告诉Spring在找不到匹配 Bean 时也不报错
可以使用@Qualifier指定Bean的名称
//给该类注解一个userService类似 <bean id=userService class="UserServiceImpl">
@Service("userService")
public class UserServiceImpl implements UserService{
	...省略get/set方法
	//1.自动根据类型装配 bean
	@Autowired(required=false)
	//2.除了自动适配,还可以手动指向 Bean数据源
	//类似<property name="dao" ref = "userDao">
	@Qualifier("userDao") //规定变量dao使用userDao数据源
	private UserDao dao;
	//3.使用Resource注解实现组件装配
	//@Resource(name="userDao") 为dao属性注入名为userDao的bean
	//private UserDao dao;
	//@Resource 查找名为dao的Bean,并注入给dao属性
	//private UserDao dao;
	
	//4.可以在set方法里使用@Qualifier设置变量使用的 bean源
	public setDao(@Qualifier("userDao")UserDao dao){
		this.dao = dao;
	}
}

<!--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/beans
   	   http://www.springframework.org/schema/beans/spring-beans.xsd
   	   <!--添加context组件-->
	   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>

@Controller:标注控制器类

AOP(必须是JDK5.0或以上版本)
AspectJ

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

@AspectJ

AspectJ 5新增的功能,使用JDK 5.0注解技术和正规的AspectJ切点表达式语言描述切片

Spring通过继承AspectJ实现了以注解的方式定义增强类,大大减少了配置文件中的工作量

利用轻量级的字节码处理框架asm处理@AspectJ中所描述的方法参数名

编写增强类
package 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 org.aspectj.lang.annotation.Pointcut;
import java.util.Arrays;
/*
* 使用Aspect注解来设置增强类
*/
@Aspect
public class UserServiceLogger2 {
    private static Logger log = Logger.getLogger(UserServiceLogger2.class);
	//为service下所有方法添加增强
    @Pointcut("execution(* service..*.*(..))")
    public void pointcut(){}

//    @Before("execution(* service..*.*(..))")
	//使用Before注解,参数是调用切入点pointcut()方法
    @Before("pointcut()")
    public void before(JoinPoint jp){
        log.info("调用" + jp.getTarget() + " 的 " + jp.getSignature() + "方法,方法参数:"+ Arrays.toString(jp.getArgs()));
    }
    //使用AfterReturning注解,参数是调用切入点pointcut()方法
    @AfterReturning(pointcut = "execution(* service..*.*(..))",returning = "result")
    public void afterReturning(JoinPoint jp, Object result){
        log.info("调用" + jp.getTarget() + " 的 " + jp.getSignature() + "方法,方法返回值:"+ result);
    }
}
<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"
   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-3.2.xsd
    http://www.springframework.org/schema/aop
    http://www.springframework.org/schema/aop/spring-aop.xsd">
	//扫描注解<!--指定需要扫描的基类包,多个包可以用逗号隔开-->
    <context:component-scan base-package="service,dao"/>
    <bean class="aop.UserServiceLogger2"/>
    <!--启动对spring AOP的AspectJ注解的支持-->
    <aop:aspectj-autoproxy/>
</beans>
dao层实现类型
@Repository("userDao")
public class UserDaoImpl implements UserDao {
    /**
     * 说话方法
     * @param uname
     * @param content
     */
    @Override
    public void say(String uname, String content) {
        System.out.println(uname+"说:"+content);
    }
}
service层实现类
@Service("userService")
public class UserServiceImpl implements UserService {
    //声明接口类型的引用,和具体实现类耦合
    @Autowired  //按类型装配
    private UserDao dao;	
	/**
     * 说话方法
     */
    @Override
    public void say(String uname,String content) {
        dao.say(uname,content);
    }
}
测试类
public class test {
	@Test
 public void AspectJTest(){
    ApplicationContext context =
            new ClassPathXmlApplicationContext("ApplicationContentNotes.xml");
        UserService userService = (UserService) context.getBean("userService");
       	userService.say("何","哈哈");
	}
}

测试结果:
在这里插入图片描述

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值