为什么要学习spring?
spring提供了ioc容器,不需要自己创建和管理对象,由spring来创建和管理。
spring提供了面向切面编程,不修改源代码的情况下对功能进行增强。
spring提供了事务支持,使事务操作变得更加方便。
spring方便集成其他框架,例如mybatis。
IOC
控制反转,由spring来创建对象以及对象之间的调用。最主要的作用就是降低耦合度。
对象之间调用的传统方式:
class A{ class B{
add(){ put(){}
B b = new B(); }
b.put();
}
}
工厂模式:
class A{ class B{
add(){ put(){}
B b =Factory.getB() }
b.put();
}
}
class Factory{
public static B getB(){
return new B();
}
}
耦合度不可能不存在,只能是降低到最小。
IOC底层原理:
ioc主要是由xml解析、工厂模式以及反射实现的。
1.在xml文件里配置要创建的对象
<bean id="别名" class="类路径"></bean>
2.创建工厂类
class Factory{
public static B getB(){
String classValue =类路径 //这是由xml解析得到的
Class clazz =Class.forName(classValue); //反射机制,通过类名得到该类的字节码文件
return (强转)clazz.newInstance(); //newInstance()方法默认调用类的空参构造器创建对象
}
ioc容器底层的本质就是对象工厂。
基于注解方式创建对象以及注入属性
创建对象的注解
@Component 普通组件
@Controller 用于web层
@Service 用于业务逻辑层
@Repository 用于持久层(数据层)
属性注入(对象类型的属性)
@AutoWired (最常用) 根据属性类型自动注入
@Qualifier 根据属性名称注入,这个注解需要和@AutoWired 一起使用,当一个接口有多个实现类,仅@AutoWired无法确定是注入哪个实现类的对象,需要用 @Qualifier (value="类名小写")
@Resource 可以根据类型或名称注入
@AutoWired 和@Resource 的区别:
@AutoWired默认按照属性类型注入,根据名称需要加@Qualifier
@Resource默认按照属性名称注入,名称找不到才会按照属性类型注入。
AOP
面向切面编程
底层原理(动态代理)
1.有接口情况,使用jdk动态代理
public interface UserDao {
public int add(int a, int b);
public String update(String id);
}
public class UserDaoImpl implements UserDao{
@Override
public int add(int a, int b) {
System.out.println("add方法执行了");
return a+b;
}
@Override
public String update(String id) {
System.out.println("update方法执行了");
return id;
}
}
创建代理对象需要用到Proxy类的newProxyInstance()方法,三个参数为类加载器,接口,InvocationHandler接口的实现类对象
public class JDKProxy {
public static void main(String[] args) {
Class[] interfaces = {UserDao.class};
UserDaoImpl userDao = new UserDaoImpl();
//接口等于实现类创建代理对象
UserDao dao =(UserDao) Proxy.newProxyInstance(JDKProxy.class.getClassLoader(), interfaces, new UserDaoProxy(userDao));
int result = dao.add(1, 2);
System.out.println("result"+result);
}
}
//创建代理对象代码
class UserDaoProxy implements InvocationHandler {
//把需要增强的方法所在的类的对象传递过来
//通过有参构造传递
private Object obj;
public UserDaoProxy(Object obj) {
this.obj = obj;
}
//增强的逻辑代码
//proxy代表代理类,method是代理类和被代理的同名方法,args方法参数
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
//方法之前的增加处理
System.out.println("方法之前执行"+method.getName()+":传递的参数.."+ Arrays.toString(args));
//被增加的方法的执行
Object res = method.invoke(obj, args);
//方法之后的增加处理
System.out.println("方法之后输出"+obj);
return res;
}
}
2.没有接口情况,使用cglib动态代理
public class UserDao {
public void addUser() {
System.out.println("添加方法");
}
public void deleteUser() {
System.out.println("删除方法");
}
}
public class CglibProxy implements MethodInterceptor{
//创建代理方法
public Object createProxy(Object object) {
//创建一个动态类对象
Enhancer enhancer = new Enhancer();
//确定需要增强的类 设置其父类
enhancer.setSuperclass(object.getClass());
//添加回调函数
enhancer.setCallback(this);
//返回创建的代理类
return enhancer.create();
}
//proxy cglib根据定义的父类生成的代理对象
//method 拦截的方法
//args 拦截的方法的参数数组
//methProxy 方法的代理对象 用于执行父类的方法
@Override
public Object intercept(Object proxy, Method method, Object[] args, MethodProxy methProxy) throws Throwable {
//方法执行之前
//目标方法执行
Object obj = methProxy.invokeSuper(proxy, args);
//方法执行之后
return obj;
}
}
public class CglibTest {
public static void main(String[] args) {
//创建代理对象
CglibProxy cglibProxy = new CglibProxy();
//创建目标对象
UserDao userDao = new UserDao();
//将目标对象传入代理对象中 获取增强后的方法
UserDao userDao2 = (UserDao) cglibProxy.createProxy(userDao);
//执行
userDao2.addUser();
userDao2.deleteUser();
}
}
spring的bean默认是单例模式的,可以将singleton改为prototype变为多实例。
单例模式分为懒汉式和饿汉式
饿汉式单例模式(提前创建好)
1.首先将类的构造器声明为私有,不能在类外创建对象
2.声明一个静态属性
private static 类名 对象= new 类名()
3.写一个静态方法用于返回创建好的一个实例对象
public static 类名 getInstance(){
return 对象;
}
懒汉式单例模式(要用的时候才创建)(线程不安全,可加synchronized优化)
1.同样将构造器定义为私有
2.声明静态变量,不赋对象
3.在静态方法中给静态变量赋一个new对象,然后返回。
但是在静态方法中需要判断是不是已经new了对象,若没有则创建,有则使用原来的。不加判断会导致每次都是一个地址不同的对象