Spring学习日记第二天—SpringIOC

SpringIOC

常见的几个注解

扫描注解

使用前需要勾选上
在这里插入图片描述
base-package 需要扫描的位置的路径
在这里插入图片描述

一、@Component

@Component是一个元注解,当使用基于注解的配置和类路径扫描的时候,这些类就会被实例化。就是说它注解的类会在contex配置扫描到的时候加载,没有被他注解的则不会加载。
在这里插入图片描述

二、@Controller

@controller是一个用于控制层的注解,用来描述此处为控制层,他与@Component使用方面暂时无区别
在这里插入图片描述

三、@Service

@Service 是一个用于业务层的注解,用来描述此处是业务层,他与@Component使用方面暂时无区别
在这里插入图片描述

四、@Repository

@Repository是一个用于持久层(daoimp)的注解,用来描述此处是持久层,他与@Component使用方面暂时无区别
在这里插入图片描述

五、@Resource

@Resource 会根据name属性去IOC中寻找对应,昨天的XML文件配置后,使用时需要进行Setter设置,而此注解就是免除Setter设置
在这里插入图片描述

六、@Autowired

@Autowired 默认会根据类型去IOC容器中查询对应的对象,如果想根据name查找则需要用到@Qualifier(“name”)

七、@Qualifier

@Qualifier 配合@Autowired使用




JAVA配置的实现

在spring4以候,提供了基于JAVA类的方式实现替代XML文件

一、代码案例
其一
@Configuration // 该注解表示该类相当于一个XML文件,等价于 ApplicationContext.xml
public class JavaConfig {
	@Bean	// 该注解理解为注册,就相等于XML文件中 <bean class="User" name="getuser" />
	public User getuser(){
		User user=new User();
		return user;
	}
}

运行代码

public static void main(String[] args) {
		ApplicationContext ac=new AnnotationConfigApplicationContext(JavaConfig.class);
		//注意此处需要用 AnnotationConfigApplicationContext 方法加载
		User bean = ac.getBean(User.class);	
		bean.hello();
	}
其二
@Configuration
//@ComponentScan("com.sxt.pojo") //在需要扫描的类头部开启扫描	
//@ComponentScans
(value={@ComponentScan("com.sxt.pojo")........})
//与上方式一样,此处为扫描多个

public class JavaConfig {
	@Bean
	public User getuser(){
		User user=new User();
		return user;
	}
}

@Component //此注解意为:扫描这个类
public class User {
	public void hello() {
		// TODO Auto-generated method stub
	System.out.println("hello");
	}
	public static void main(String[] args) {
		ApplicationContext ac=new AnnotationConfigApplicationContext(JavaConfig.class);
		User bean = ac.getBean("user",User.class);	 //这里的user为User类名,User类名全部大写则这里也
		//需要大写,全部小写则全部小姐,首字母大写则全部小写
		bean.hello();
	}

使用JAVA代替XML配置在SpringBoot中被广泛应用





Profile

用于方便在各种环境中切换
一、存储

在这里插入图片描述

二、配置
@Configuration
public class JavaConfig {
	@Bean
	@Profile("dev")
	public DataSourceUtils getDevDataSource() {
		return new DataSourceUtils("http://192.168.1.110", "admin", "admin");
	}//其一 开发环境
	@Bean
	@Profile("pro")
	public DataSourceUtils getProDataSource() {
		return new DataSourceUtils("http://192.168.1.120", "root", "root");
	}//其二生产环境
	@Bean
	@Profile("test")
	public DataSourceUtils getTestDataSource() {
		return new DataSourceUtils("http://192.168.1.119", "test", "test");
	}//其三测试环境
}

三、测试
public class TestProfile {
	public static void main(String[] args) {
		AnnotationConfigApplicationContext ac=new AnnotationConfigApplicationContext();
		ac.getEnvironment().setActiveProfiles("dev");
		ac.register(JavaConfig.class);
		ac.refresh();//刷新
		DataSourceUtils bean = ac.getBean(DataSourceUtils.class);
		System.out.println(bean);
	}
}

以上的内容会穿插在开发当中,java配置的实现以及一些常见的注解,会使用,理解就行。而对于以下内容则需要掌握。

Bean的作用域

在这里插入图片描述

在Bean的定义的时候,bean有一个属性scope,他有4个值,prototype、request表示一次请求有效、session表示一次会话有效、singleton这个值是默认的,即为单例模式,它表示只会有一个对象,当用容器多次获取时都是这一个对象。而protorype类型则表示有多个对象它是原型模式,当容器多次获取时会有不同的地址。

三种设计模式

一、单例模式

单例模式的核心是保证一个类只有一个new出来的对象,并且是他自己创建出来的,并且提供一个访问的全局节点

单例模式它有一系列的实现方式:
在这里插入图片描述
使用单例模式的目的是为了保证一个类只有一个实例的存在

二、原型模式

使用原型模式可以帮助我们解决大量new关键字来创建对象的烦恼。原型模式我们也称为克隆模式,即一个某个对象为原型克隆出来一个一模一样的对象,该对象的属性和原型对象一模一样。而且对于原型对象没有任何影响。原型模式的克隆方式有两种:浅克隆和深克隆

1、浅克隆

克隆的对象必须实现Cloneable,Serializable这两个接口
在这里插入图片描述
然后重写克隆方法就行
在这里插入图片描述
然后克隆
在这里插入图片描述

浅克隆模型图

在这里插入图片描述
假设在克隆出来的新对象中需要修改某个属性则直接set修改就行
但是随之而来的就是克隆导致的问题:虽然产生了两个完全不同的对象,但是被复制的对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用都仍然指向原来的对象。即原对象没有被克隆
所以就需要用到深克隆

2、深克隆

被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量。那些引用其他对象的变量将指向被复制过的新对象,而不再是原有的那些被引用的对象。换言之,深克隆就是把所有关系都复制了一遍,而不是像浅克隆那样只复制了表面。

深克隆模型图

在这里插入图片描述
而深克隆又分为两种方式

第一种方式:在浅克隆的基础上实现深克隆

在这里插入图片描述
在克隆时将birth属性也克隆一份,如果需要多个则将多个一一克隆,即需要多少个引用,则克隆多少个。

第二种方式:通过序列化和反序列化实现深克隆在这里插入图片描述

将原对象存贮进文件中,即序列化
在这里插入图片描述
然后再将对象从文件中读取出来,即反序列化,这时候读取出来的对象是一个新的对象,这样就达到了深度克隆的目的—>产生另一个对象但是是和原对象相同的属性
在这里插入图片描述

使用原型模式和直接new对象方式的比较

原型模式适用于我们需要大量生产同一类型对象的时候,他相比于传统直接new的方式会更加的快。

举例:用两种方式生产1000个对象
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

所以通过clone的方式在获取大量对象的时候性能开销基本没有什么影响,而new的方式随着实例的对象越来越多,性能会急剧下降

三、代理模式

为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个对象不适合或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。

1、静态代理

案例:购买科技枪
在某个地方有一个商店

public interface PatternStaticService {
	public String shop(String msg) ;//商店
}

然后在商店里有一件我想要的东西

public class PatternStaticServiceImp implements PatternStaticService{
	@Override
	public String shop(String msg) {
		System.out.println("我想要的是:"+msg);
		return msg;
	}
}

然后我开始了我的购买之路

public class TestService {
	public static void main(String[] args) {
		//几经周折我寻找到了商店的位置(获取目标对象)
		PatternStaticService target=new PatternStaticServiceImp();
		//然后找到了老板(寻找代理对象)
		PatternProxy proxy=new PatternProxy(target);
		//我跟老板说我要一把科技枪(让代理对象去执行增强方法)
		String hello = proxy.shop("科技枪");
		//然后老板给了我一把科技枪,说他帮我增强了一波(最终返回值)
		System.out.println(hello);
	}
}

然后我问老板是怎么增强的,老板告诉我说

public class PatternProxy implements PatternStaticService{
	private PatternStaticService tagert;//声明成员变量,即为找到目标对象
	//通过构造的方式传递
	public PatternProxy(PatternStaticService tagert) {
		super();
		this.tagert = tagert;
	}
	@Override
	public String shop(String msg) {
		System.out.println("告诉老板我的需求");
		String msg1 = tagert.shop(msg);
		System.out.println("老板知道之后,在我的需求上增强了一下");
		return "给了我一把:增强型"+msg1;
	}
}

然后就有了结果
在这里插入图片描述
但是如果用这种方法的话,每当我需要增强一种功能的时候我就需要在接口上写,多了的时候就很繁杂,这样不利于我们后期 的管理修改。 所以就引入动态代理

2、动态代理

动态代理又分两种类型:

①、JDK中的动态代理
动态代理中我们会用到一个方法:java.lang.reflect.Proxy 包下的
**Proxy.newProxyInstance(loader, interfaces, h)**
Proxy.newProxyInstance(loader, interfaces, h)
loader:类加载器
interfaces:接口数组
h:方法调用处理器

接口中定义两个目标对象

public interface PatternStaticService {
	public String shop(String msg) ;
	
	public void fun(String msg) ;
}

实现定义的两个目标对象

public class PatternStaticServiceImp implements PatternStaticService{
	@Override
	public String shop(String msg) {
		System.out.println("传递过来的是:"+msg);
		return msg;
	}

	@Override
	public void fun(String msg) {
		System.out.println("传递过来的是:"+msg);
	}
}

主方法

public static void main(String[] args) {
		//获取目标对象
		PatternStaticService target=new PatternStaticServiceImp();
		//通过JDK动态获取代理对象
		PatternStaticService proxy = (PatternStaticService) //这里向上转型
				Proxy.newProxyInstance(target.getClass().getClassLoader()
				, target.getClass().getInterfaces()//实现目标对象的所有接口
				, new InvocationHandler() {
					/**
					 * 动态代理核心方法,当代理对象执行的时候具体执行的方法
					 */
					@Override
					public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
						System.out.println("代理对象名称:"+method.getName());//得到目标方法的名称
						System.out.println("执行动态代理之前");
						Object obj=method.invoke(target, args);
						System.out.println("执行动态代理之后");
						if (obj!=null&&obj instanceof String) {
							String msg=(String) obj;
							return msg.toUpperCase();
						}
						return null;
					}
				});
		//通过代理对象执行目标对象的方法
		String shop = proxy.shop("aaa");
		System.out.println("返回的结果是:"+shop);
		proxy.fun("bbb");//他没有返回值
	}

运行后结果是:
在这里插入图片描述
②、cglib中的动态代理
使用这种方式需要导入一个第三方依赖包
在这里插入图片描述
目标对象

public class PatternStaticServiceImp {
	public String shop(String msg) {
		System.out.println("目标对象是:"+msg);
		return "给-"+msg+"-附了魔";
	}
	public void fun(String msg) {
		System.out.println("目标对象是:"+msg+"    但是我没有给他附魔");
	}
}

创建代理工厂

/**
 * 这是一个代理对象的工厂类,他用来生产创建代理对象
 */
public class CglibFactory implements MethodInterceptor{
	//目标对象
	private PatternStaticServiceImp target;
	//构造方法
	public CglibFactory(PatternStaticServiceImp target) {
		super();
		this.target = target;
	}
	/**
	 * 创建代理对象的方法
	 */
	public PatternStaticServiceImp createProxyInstane(){
		//获取Enhancer对象
		Enhancer  enhancer=new Enhancer();
		//告诉代理对象他的父类是谁
		enhancer.setSuperclass(PatternStaticServiceImp.class);
		//设置回调的对象
		enhancer.setCallback(this);
		//返回代理对象
		return (PatternStaticServiceImp) enhancer.create();
		//因为父类是UserServiceImp类型,所以就需要向上转型
	}
	/**
	 * 代理对象具体执行的方法
	 */
	@Override
	public Object intercept(Object arg0, Method method, Object[] args, 
	MethodProxy arg3) throws Throwable {
		System.out.println("执行代理之前:");
		Object obj = method.invoke(target, args);
		System.out.println("执行代理之后:");
		System.out.println(obj);
		return obj;
	}
}

运行

public class TestCglibProxy {
	public static void main(String[] args) {
		PatternStaticServiceImp target=new PatternStaticServiceImp();
		CglibFactory factory=new CglibFactory(target);
		PatternStaticServiceImp proxy = factory.createProxyInstane();
		proxy.shop("科技枪");
		proxy.fun("无用大棒");//没有返回
	}
}

结果
在这里插入图片描述

静态代理的话在接口中有多少个方法就需要重写多少次,而动态代理则免除了多次创建代理的烦恼。

补充

IOC源码分析

在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值