06-2 spring框架

复习:


Spring贯穿了整个三层架构
对象的容器,管理项目中的所有对象
设计理念


IOC


    控制反转 -> 思想
    创建对象的方式被反转了, 原来由java程序自己创建对象, 自己管理依赖
    用了spring之后, 由spring创建对象, 注入依赖关系. 我们只需要编写配置文件即可

    DI技术: 依赖注入,它是ioc思想的主要实现方式
    方式:
        1. 属性注入
        2. set注入
        3. 构造器注入

AOP


    面向切面(后面有详细介绍)

详细配置
配置文件: 位置任意, 名字任意
    建议写成 src/applicationContext.xml

<bean>元素的配置
    id: 取出对象使用的字符序列, 1-不能重复 2-不能有特殊字符 (旧属性,基本废弃)
    name:  取出对象使用的字符序列 1-能重复 2-能有特殊字符 (新属性)
    class: 完整类名

    生命周期方法配置
    init-method : 创建对象后调用
    destroy-method : 对象被销毁前调用

    scope属性:
    singleton : 单例模式, 容器创建时就会创建对象, 每次都是同一个对象
    prototype : 多例模型, 每次获取才会创建对象, 每次都是一个新的对象


【注解方式配置】

可以看以下这篇博主的文章,写的详细

https://blog.csdn.net/u010648555/article/details/76299467

    1. 导包
        4 :expression,beans,context,core
        2 :2个日志jar包
        1 : spring-aop-4.2.4.RELEASE.jar(aop的jar包)    

    2. 配置src/applicationContext.xml
        
  在顶部添加xmlns:context="http://www.springframework.org/schema/context"

  在xsi:schemaLocation属性中添加2行网址

 <beans xmlns="http://www.springframework.org/schema/beans"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" 
        添加的context约束
        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.xsd">
        <!-- 添加context标签,用于扫描指定的包和他的子孙包,若包下的类有注解,就构造对象,并放到spring容器 -->
        <context:component-scan base-package="com.bwf.bean" />
        
        <!-- 如果搜索路径:base-package="com.bwf",那么扫描的就是com.bwf下所有的包-->
    
</beans>


    3. 根据类上的注解@Component("user") 中的名字
    取出user对象

组件

一下四个都能作为spring注解,可以划分不同层之间的实例,方便区分
@Component :标准一个普通的spring Bean类。 
@Repository:标注一个DAO组件类。 
@Service:标注一个业务逻辑组件类。 
@Controller:标注一个控制器组件类。
     注入属性

    @Value("李四")
    private String name;

    或
    @Value("李四")
    public void setName(String name) {
        this.name = name;
    }

     引用类型注入    
  

    方式1: 根据类型自动装配
    @Autowired
    private Car car;
    
    方式2: 根据类型和name装配
    若有2个相同类型,则需要额外指定容器中的对象名
    @Autowired
    @Qualifier("car2")
    private Car car;

    方式3: 根据name获取
    @Resource(name="car2")
    private Car car;

推荐使用:@Resource注解在字段上,这样就不用写setter方法了,并且这个注解是属于J2EE的,减少了与spring的耦合。这样代码看起就比较优雅。


  多例配置

 @Scope("prototype")
    public class User{    

 

 

package com.bwf.a_annotation;

import org.junit.Test;
import org.springframework.context.support.ClassPathXmlApplicationContext;

import com.bwf.bean.User;

public class Demo1 {

	@Test
	public void fn1(){
		
		ClassPathXmlApplicationContext ac = new ClassPathXmlApplicationContext("applicationContext.xml");
		
		User u1 = (User) ac.getBean("user");
		User u2 = (User) ac.getBean("user");		
		System.out.println(u1 == u2);		
		ac.close();				
	}	
}

注意:如果调用了close方法销毁对象,那么多例配置生成的对象不会被销毁,只有单例生成的对象才会被销毁

【spring整合junit单元测试】

    1. 导包
        spring-test-4.2.4.RELEASE.jar

    2. 写一个测试类

package com.bwf.b_test;

import javax.annotation.Resource;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.bwf.bean.User;

//让j测试运行于spring运行环境
@RunWith(SpringJUnit4ClassRunner.class)
//Spring整合JUnit4测试时,使用注解引入配置文件
@ContextConfiguration("classpath:applicationContext.xml")
public class Demo1 {
    //3. 把测试类中的成员属性用容器中的对象赋值
	//@Autowired容器内的同一个类的对象只有一个时,可以用自动装配
    //有多个对象可以用resource
    @Resource(name="user")
	private User u;
	//  4. 在测试方法中使用
    //    @Test
	@Test
	public void fn1(){
		System.out.println(u);
	}
	//可以有多个
	@Test
	public void fn2(){
		System.out.println(u);
	}

	
}


【AOP思想的介绍】


    Aspect Oriented Programming
    面向切面编程: 面向对象思想的一种升级
    横向重复代码, 纵向提取

 

    生活中的例子
    老师的笔记中出了一个小错
    1. 每个同学自己改一下
    2. 老师改一下 (更好的方案)


    开发中的案例
    1. 用过滤器解决所有Serlvet的编码问题

(装饰模式强化过的getParameter方法,去除get方法产生的中文乱码问题)

https://blog.csdn.net/qq_36194262/article/details/83507615
    2. 用动态代理解决service中所有方法的打开事务, 提交事务出现异常回滚事务的操作


【Spring AOP】


    Spring本质就是个容器, 帮我们创建对象
    所以它可以在创建对象时, 根据我们的要求直接生成代理对象

【生成方式】


    1. 动态代理

java的原生动态代理

概念参考自

https://www.cnblogs.com/xdp-gacl/p/3971367.html

package com.bwf.c_proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import com.bwf.service.UserService;

public class UserServiceProxyFactory implements InvocationHandler {
	/*本类用来强化userservice方法,主方法通过构造本类对象,
          传入原本的对象,返回的是增强过的对象*/
	private UserService us;	
	//传入原本的对象,准备强化
	public UserServiceProxyFactory(UserService us) {
		super();
		this.us = us;
	}


	/**
	 * 获得us的代理对象 具有事务的功能
	 * @return
	 */
	public UserService getProxy(){

	/*newProxyInstance这个方法有三个参数,第一个是被代理对象的类加载器,第二个是该类的接口,所以说被代理的对象必须要实现接口,第三个参数是InvocationHandler 接口的实现类
这里很巧妙,通过当前类实现InvocationHandler接口,重写invoke方法(写你要增强的代码),这时候第三个参数就可以传this(当前对象,因为我实现了InvocationHandler接口)*/
		Object proxy = Proxy.newProxyInstance(us.getClass().getClassLoader()
					, us.getClass().getInterfaces(), this);
	
		
		return (UserService) proxy;
	}

/*
                      * 在invoke方法编码指定返回的代理对象干的工作
                      * proxy :  代理对象 
                      * method: 代理方法调用的对象
                      * args:    方法参数
                      * 
                      * 当调用代理对象执行方法时,
                      * 实际上执行的都是invoke方法里面的代码,
                      */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
		System.out.println("打开事务");
		Object res = method.invoke(us, args);
		System.out.println("提交事务");
		return res;
	}
	
}

构造该类对象传入userservice对象,调用getproxy方法即可获得增强过的userservice

    2. cglib代理

package com.bwf.c_proxy;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

import org.springframework.cglib.proxy.Enhancer;
import org.springframework.cglib.proxy.MethodInterceptor;
import org.springframework.cglib.proxy.MethodProxy;

import com.bwf.service.UserService;
import com.bwf.service.UserServiceImpl;

public class UserServiceProxyFactory2 implements MethodInterceptor {
	/**
	 * cglib的代理方式
	 * 获得us的代理对象 具有事务的功能
	 * @return
	 */
	public UserService getProxy(){
	
		// 帮我们生成代理对象
		Enhancer enhancer = new Enhancer();
		// 设置对谁进行代理
		enhancer.setSuperclass(UserServiceImpl.class);
		// 设置代理要做什么
		enhancer.setCallback(this);
		// 生成代理对象
		UserService us = (UserService) enhancer.create();
		
		return us;		
	}

	/**
	 * 原始对象    obj
	 * 原始方法    method
	 * 原始参数    args
	 * 代理方法    methodProxy
	 */
	@Override
	public Object intercept(Object obj, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
		System.out.println("打开事务");
		Object res = methodProxy.invokeSuper(obj, args);
		System.out.println("提交事务");
		return res;
	}



	
}

构造该对象,调用getproxy方法即可获得增强过的userservice

    使用规则: 如果能用动态代理, 就用动态代理; 否则就用cglib代理

【AOP名词】

中文名英文名解释
连接点Join point目标对象中, 可以增强的方法
切入点Pointcut目标对象中, 已经增强的方法
通知     Advice增强的代码
目标对象Target object被代理的对象
织入Weaving将通知应用到切入点的过程
代理 AOP proxy将通知织入切入点, 最后形成代理
切面Aspect通知 + 切入点

 

 

 

 

 

 

 

 

【spring aop 配置】

注意:aop页用xml文件配置,当然也可以用注解,但是用注解太麻烦,每一个要配置的类都要写注解.

    1. 导包
        4个核心包(core,expression,beans,context)
        2个新老日志jar包
        2个在srping的lib中的包
        spring-aop-4.2.4.RELEASE.jar    
        spring-aspects-4.2.4.RELEASE.jar
        2个(都在spring依赖包中):
        com.springsource.org.aspectj.weaver-1.6.8.RELEASE.jar

        位置:spring-framework-3.0.2.RELEASE-dependencies\org.aspectj\com.springsource.org.aspectj.weaver\1.6.8.RELEASE

        com.springsource.org.aopalliance-1.0.0.jar

       位置:spring-framework-3.0.2.RELEASE-dependencies\org.aopalliance\com.springsource.org.aopalliance\1.0.0

    2. 书写目标对象和通知

UserServiceImpl类用于产生目标对象

package com.wowowo.service.impl;
import com.wowowo.service.UserService;
public class UserServiceImpl implements UserService {

	@Override
	public void insert() {
		System.out.println("增");
	}
	@Override
	public void delete() {
		System.out.println("删");
		//会抛异常
		int x = 1 / 0;
	}
}

通知写到一个MyAdvice类里面

    注意:

通知的类型解释
before前置通知(方法执行前)
after-returning后置通知(一旦出现异常, 就不会出现)
 after-throwing后置通知 (出现了异常, 才会出现)
 after 后置通知 (就算出现异常, 也会出现)
around环绕通知(包裹在原来方法的前后出现)

   
    

 

 

 

 


      * 环绕通知的方法必须声明为
    public Object around(ProceedingJoinPoint pjp) throws Throwable
    并通过Object retVal = pjp.proceed();调用原来的方法

package com.wowowo.springaop;
import org.aspectj.lang.ProceedingJoinPoint;
public class MyAdvice {
	//方法调用前执行
	public void before() {
		System.out.println("before");
	}
	//方法调用后执行,方法出现异常就不执行
	public void afterReturning() {
		System.out.println("afterReturning");
	}
	//方法出现异常时执行
	public void afterThrowing() {
		System.out.println("afterThrowing");
	}
	//无论是否出现异常,都会在方法结束后执行
	public void after() {
		System.out.println("after");
	}
	// 环绕通知
	public Object around(ProceedingJoinPoint pjp) throws Throwable {
		System.out.println("打开事务");
		// 调用原来的方法
		Object retVal = pjp.proceed();
		System.out.println("提交事务");
		return retVal;
	}
}


    3. 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:context="http://www.springframework.org/schema/context"
	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 name="us" class="com.wowowo.service.impl.UserServiceImpl">
	</bean>
	<bean name="ad" class="com.wowowo.springaop.MyAdvice">
	</bean>
	<aop:config>
		<!-- 切面:引用通知的id -->
		<aop:aspect ref="ad">
			<!-- 切入点: 写表达式去筛选连接点 -->
			<aop:pointcut id="pc"
				expression="execution(* com.wowowo.service.impl.*ServiceImpl.*(..))" />
			<!-- 织入: 把通知织入到切入点中 . 需要切入点id 和通知中的方法名 -->
			<!-- 前置通知  -->
			<aop:before pointcut-ref="pc" method="before"/>
			<!-- 后置通知 (一旦异常就没有了) -->
			<aop:after-returning pointcut-ref="pc" method="afterReturning"/>
			<!-- 异常通知 -->
			<aop:after-throwing pointcut-ref="pc" method="afterThrowing"/>
			<!-- 后置通知(就算异常也会有)  -->
			<aop:after pointcut-ref="pc" method="after"/>
			<!-- 环绕通知 -->
			<aop:around pointcut-ref="pc" method="around"/>
		</aop:aspect>
	</aop:config>
</beans>

userService类:

package com.bwf.service;

import org.springframework.stereotype.Component;

@Component("us")
public class UserServiceImpl implements UserService {

	@Override
	public void delete() {
		System.out.println("删");
	}

	@Override
	public void update() {
		System.out.println("改");	
        //会抛出异常:java.lang.ArithmeticException: / by zero
		int x = 1/0;
	}


}

配置完成可以写个测试单元进行一下测试

package com.wowowo.springaop;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit4.SpringJUnit4ClassRunner;

import com.wowowo.service.UserService;
import com.wowowo.service.impl.UserServiceImpl;
//
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration("classpath:com/wowowo/springaop/applicationContext.xml")
public class Demo01 {
	@Autowired
	//注解方式自动装配userservice
	private UserService us;
	//springaop方式实现
	@Test
	public void test1() {
		us.insert();
	}
	@Test
	public void test2() {
		us.delete();
	}

}

test1和test2方法被强化后的区别:

  1. test1方法没有异常,会调用afterreturning方法
  2. test2方法会抛异常,会调用afterthrowing方法
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值