TODAY Context 是一个轻量级依赖注入框架。
@Component
@Component
注解就会标识为一个Bean不论多少层@Target({ ElementType.TYPE, ElementType.METHOD }) public @interface Component { /** @return bean name */ String[] value() default {}; /** @return bean's scope */ Scope scope() default Scope.SINGLETON; String[] initMethods() default {}; String[] destroyMethods() default {}; }
@Singleton
@Component(scope = Scope.SINGLETON) @Target({ ElementType.TYPE, ElementType.METHOD }) public @interface Singleton { // bean name String[] value() default {}; String[] initMethods() default {}; String[] destroyMethods() default {}; }
@Prototype
@Retention(RetentionPolicy.RUNTIME) @Component(scope = Scope.PROTOTYPE) @Target({ ElementType.TYPE, ElementType.METHOD }) public @interface Prototype { // bean name String[] value() default {}; String[] initMethods() default {}; String[] destroyMethods() default {}; }
@Configuration
@Target(ElementType.TYPE) @Component(scope = Scope.SINGLETON) public @interface Configuration { }
@Service
@Component(scope = Scope.SINGLETON) @Target({ ElementType.TYPE, ElementType.METHOD }) public @interface Service { String[] value() default {};// bean names }
@Autowired
注入@Resource
注入@Inject
注入PropertyValueResolver
:@FunctionalInterface public interface PropertyValueResolver { default boolean supports(Field field) { return false; } PropertyValue resolveProperty(Field field) throws ContextException; }
@Controller @SuppressWarnings("serial") public class LoginController implements Constant, ServletContextAware { private String contextPath; @Autowired private UserService userService; //@Inject @Resource private BloggerService bloggerService; @GET("/login") public String login(@Cookie String email, String forward, Model model) { model.attribute(KEY_EMAIL, email); model.attribute("forward", forward); return "/login/index"; } @POST("/login") @Logger(value = "登录", // content = "email:[${email}] " // + "passwd:[${passwd}] "// + "input code:[${randCode}] "// + "in session:[${randCodeInSession}] "// + "forward to:[${forward}] "// + "msg:[${redirectModel.attribute('msg')}]"// ) public String login(HttpSession session, @Cookie(KEY_EMAIL) String emailInCookie, @RequestParam(required = true) String email, @RequestParam(required = true) String passwd, @RequestParam(required = true) String randCode, @RequestParam(required = false) String forward, @Session(RAND_CODE) String randCodeInSession, RedirectModel redirectModel) // { session.removeAttribute(RAND_CODE); if (!randCode.equalsIgnoreCase(randCodeInSession)) { redirectModel.attribute(KEY_MSG, "验证码错误!"); redirectModel.attribute(KEY_EMAIL, email); redirectModel.attribute(KEY_FORWARD, forward); return redirectLogin(forward); } User loginUser = userService.login(new User().setEmail(email)); if (loginUser == null) { redirectModel.attribute(KEY_EMAIL, email); redirectModel.attribute(KEY_FORWARD, forward); redirectModel.attribute(KEY_MSG, email + " 账号不存在!"); return redirectLogin(forward); } // �� 略 } @GET("/logout") public String logout(HttpSession session) { session.invalidate(); return "redirect:/index"; } @Override public void setServletContext(ServletContext servletContext) { this.contextPath = servletContext.getContextPath(); } }
public class AutowiredPropertyResolver implements PropertyValueResolver { private static final Class<? extends Annotation> NAMED_CLASS = ClassUtils.loadClass("javax.inject.Named"); private static final Class<? extends Annotation> INJECT_CLASS = ClassUtils.loadClass("javax.inject.Inject"); @Override public boolean supports(Field field) { return field.isAnnotationPresent(Autowired.class) || field.isAnnotationPresent(Resource.class) || (NAMED_CLASS != null && field.isAnnotationPresent(NAMED_CLASS)) || (INJECT_CLASS != null && field.isAnnotationPresent(INJECT_CLASS)); } @Override public PropertyValue resolveProperty(Field field) { final Autowired autowired = field.getAnnotation(Autowired.class); // auto wired String name = null; boolean required = true; final Class<?> propertyClass = field.getType(); if (autowired != null) { name = autowired.value(); required = autowired.required(); } else if (field.isAnnotationPresent(Resource.class)) { name = field.getAnnotation(Resource.class).name(); // Resource.class } else if (NAMED_CLASS != null && field.isAnnotationPresent(NAMED_CLASS)) {// @Named name = ClassUtils.getAnnotationAttributes(NAMED_CLASS, field).getString(Constant.VALUE); } // @Inject or name is empty if (StringUtils.isEmpty(name)) { name = byType(propertyClass); } return new PropertyValue(new BeanReference(name, required, propertyClass), field); } }
看到这你应该明白了注入原理了
@Autowired
构造器注入// cn.taketoday.web.servlet.DispatcherServlet public class DispatcherServlet implements Servlet, Serializable { private static final Logger log = LoggerFactory.getLogger(DispatcherServlet.class); /** exception resolver */ private final ExceptionResolver exceptionResolver; /** Action mapping registry */ private final HandlerMappingRegistry handlerMappingRegistry; /** intercepter registry */ private final HandlerInterceptorRegistry handlerInterceptorRegistry; private final WebServletApplicationContext applicationContext; private ServletConfig servletConfig; @Autowired public DispatcherServlet(// ExceptionResolver exceptionResolver, // HandlerMappingRegistry handlerMappingRegistry, // WebServletApplicationContext applicationContext, HandlerInterceptorRegistry handlerInterceptorRegistry) // { if (exceptionResolver == null) { throw new ConfigurationException("You must provide an 'exceptionResolver'"); } this.exceptionResolver = exceptionResolver; this.applicationContext = applicationContext; this.handlerMappingRegistry = handlerMappingRegistry; this.handlerInterceptorRegistry = handlerInterceptorRegistry; } public static RequestContext prepareContext(final ServletRequest request, final ServletResponse response) { return RequestContextHolder.prepareContext(// new ServletRequestContext((HttpServletRequest) request, (HttpServletResponse) response)// ); } @Override public void service(final ServletRequest req, final ServletResponse res) // throws ServletException, IOException // { // Lookup handler mapping final HandlerMapping mapping = lookupHandlerMapping((HttpServletRequest) req); if (mapping == null) { ((HttpServletResponse) res).sendError(404); return; } final RequestContext context = prepareContext(req, res); try { final Object result; // Handler Method final HandlerMethod method;// = requestMapping.getHandlerMethod(); if (mapping.hasInterceptor()) { // get intercepter s final int[] its = mapping.getInterceptors(); // invoke intercepter final HandlerInterceptorRegistry registry = getHandlerInterceptorRegistry(); for (final int i : its) { if (!registry.get(i).beforeProcess(context, mapping)) { if (log.isDebugEnabled()) { log.debug("Interceptor: [{}] return false", registry.get(i)); } return; } } result = invokeHandler(context, method = mapping.getHandlerMethod(), mapping); for (final int i : its) { registry.get(i).afterProcess(context, mapping, result); } } else { result = invokeHandler(context, method = mapping.getHandlerMethod(), mapping); } method.resolveResult(context, result); } catch (Throwable e) { ResultUtils.resolveException(context, exceptionResolver, mapping, e); } } protected Object invokeHandler(final RequestContext request, final HandlerMethod method, final HandlerMapping mapping) throws Throwable // { // log.debug("set parameter start"); return method.getMethod()// .invoke(mapping.getBean(), method.resolveParameters(request)); // invoke } protected HandlerMapping lookupHandlerMapping(final HttpServletRequest req) { // The key of handler String uri = req.getMethod() + req.getRequestURI(); final HandlerMappingRegistry registry = getHandlerMappingRegistry(); final Integer i = registry.getIndex(uri); // index of handler mapping if (i == null) { // path variable uri = StringUtils.decodeUrl(uri);// decode for (final RegexMapping regex : registry.getRegexMappings()) { // TODO path matcher pathMatcher.match(requestURI, requestURI) if (regex.pattern.matcher(uri).matches()) { return registry.get(regex.index); } } log.debug("NOT FOUND -> [{}]", uri); return null; } return registry.get(i.intValue()); } @Override public void init(ServletConfig servletConfig) throws ServletException { this.servletConfig = servletConfig; } @Override public ServletConfig getServletConfig() { return servletConfig; } public String getServletName() { return "DispatcherServlet"; } @Override public String getServletInfo() { return "DispatcherServlet, Copyright © TODAY & 2017 - 2019 All Rights Reserved"; } @Override public void destroy() { if (applicationContext != null) { final State state = applicationContext.getState(); if (state != State.CLOSING && state != State.CLOSED) { applicationContext.close(); final DateFormat dateFormat = new SimpleDateFormat(Constant.DEFAULT_DATE_FORMAT);// final String msg = new StringBuffer()// .append("Your application destroyed at: [")// .append(dateFormat.format(new Date()))// .append("] on startup date: [")// .append(dateFormat.format(applicationContext.getStartupDate()))// .append("]")// .toString(); log.info(msg); applicationContext.getServletContext().log(msg); } } } public final HandlerInterceptorRegistry getHandlerInterceptorRegistry() { return this.handlerInterceptorRegistry; } public final HandlerMappingRegistry getHandlerMappingRegistry() { return this.handlerMappingRegistry; } public final ExceptionResolver getExceptionResolver() { return this.exceptionResolver; } } //cn.taketoday.web.view.FreeMarkerViewResolver @Props(prefix = "web.mvc.view.") @MissingBean(value = Constant.VIEW_RESOLVER, type = ViewResolver.class) public class FreeMarkerViewResolver extends AbstractViewResolver implements InitializingBean, WebMvcConfiguration { private final ObjectWrapper wrapper; @Getter private final Configuration configuration; private final TaglibFactory taglibFactory; private final TemplateLoader templateLoader; private final ServletContextHashModel applicationModel; public FreeMarkerViewResolver(Configuration configuration, // TaglibFactory taglibFactory, TemplateLoader templateLoader, Properties settings) // { this(new DefaultObjectWrapper(Configuration.VERSION_2_3_28), // configuration, taglibFactory, templateLoader, settings); } @Autowired public FreeMarkerViewResolver(// @Autowired(required = false) ObjectWrapper wrapper, // @Autowired(required = false) Configuration configuration, // @Autowired(required = false) TaglibFactory taglibFactory, // @Autowired(required = false) TemplateLoader templateLoader, // @Props(prefix = "freemarker.", replace = true) Properties settings) // { WebServletApplicationContext webApplicationContext = // (WebServletApplicationContext) WebUtils.getWebApplicationContext(); if (configuration == null) { configuration = new Configuration(Configuration.VERSION_2_3_28); webApplicationContext.registerSingleton(configuration.getClass().getName(), configuration); } this.configuration = configuration; if (wrapper == null) { wrapper = new DefaultObjectWrapper(Configuration.VERSION_2_3_28); } this.wrapper = wrapper; ServletContext servletContext = webApplicationContext.getServletContext(); if (taglibFactory == null) { taglibFactory = new TaglibFactory(servletContext); } this.taglibFactory = taglibFactory; this.configuration.setObjectWrapper(wrapper); // Create hash model wrapper for servlet context (the application) this.applicationModel = new ServletContextHashModel(servletContext, wrapper); webApplicationContext.getBeansOfType(TemplateModel.class).forEach(configuration::setSharedVariable); this.templateLoader = templateLoader; try { if (settings != null && !settings.isEmpty()) { this.configuration.setSettings(settings); } } catch (TemplateException e) { throw new ConfigurationException("Set FreeMarker's Properties Error, With Msg: [" + e.getMessage() + "]", e); } } /** * Use {@link afterPropertiesSet} * * @since 2.3.3 */ @Override public void afterPropertiesSet() throws ConfigurationException { this.configuration.setLocale(locale); this.configuration.setDefaultEncoding(encoding); if (templateLoader == null) { this.configuration.setServletContextForTemplateLoading(servletContext, prefix); // prefix -> /WEB-INF/.. } else { configuration.setTemplateLoader(templateLoader); } LoggerFactory.getLogger(getClass()).info("Configuration FreeMarker View Resolver Success."); } @Override public void configureParameterResolver(List<ParameterResolver> resolvers) { resolvers.add(new DelegatingParameterResolver((m) -> m.isAssignableFrom(Configuration.class), // (ctx, m) -> configuration// )); resolvers.add(new DelegatingParameterResolver((m) -> m.isAnnotationPresent(SharedVariable.class), (ctx, m) -> { final TemplateModel sharedVariable = configuration.getSharedVariable(m.getName()); if (m.isInstance(sharedVariable)) { return sharedVariable; } if (sharedVariable instanceof WrapperTemplateModel) { final Object wrappedObject = ((WrapperTemplateModel) sharedVariable).getWrappedObject(); if (m.isInstance(wrappedObject)) { return wrappedObject; } throw ExceptionUtils.newConfigurationException(null, "Not a instance of: " + m.getParameterClass()); } return null; })); } /** * Create Model Attributes. * * @param requestContext * Current request context * @return {@link TemplateHashModel} */ protected TemplateHashModel createModel(RequestContext requestContext) { final ObjectWrapper wrapper = this.wrapper; final HttpServletRequest request = requestContext.nativeRequest(); final AllHttpScopesHashModel allHttpScopesHashModel = // new AllHttpScopesHashModel(wrapper, servletContext, request); allHttpScopesHashModel.putUnlistedModel(FreemarkerServlet.KEY_JSP_TAGLIBS, taglibFactory); allHttpScopesHashModel.putUnlistedModel(FreemarkerServlet.KEY_APPLICATION, applicationModel); // Create hash model wrapper for request allHttpScopesHashModel.putUnlistedModel(FreemarkerServlet.KEY_REQUEST, new HttpRequestHashModel(request, wrapper)); allHttpScopesHashModel.putUnlistedModel(FreemarkerServlet.KEY_REQUEST_PARAMETERS, new HttpRequestParametersHashModel(request)); // Create hash model wrapper for session allHttpScopesHashModel.putUnlistedModel(FreemarkerServlet.KEY_SESSION, new HttpSessionHashModel(requestContext.nativeSession(), wrapper)); return allHttpScopesHashModel; } /** * Resolve FreeMarker View. */ @Override public void resolveView(final String template, final RequestContext requestContext) throws Throwable { configuration.getTemplate(template + suffix, locale, encoding)// .process(createModel(requestContext), requestContext.getWriter()); } }
@Props
注入Properties或Bean@Autowired public PropsBean(@Props(prefix = "site.") Bean bean) { //--------- } @Autowired public PropsBean(@Props(prefix = "site.") Properties properties) { //------- } @Autowired public PropsBean(@Props(prefix = "site.") Map properties) { //------- }
@Props(prefix = "site.") Bean bean; @Props(prefix = "site.") Map properties; @Props(prefix = "site.") Properties properties
@Order(Ordered.HIGHEST_PRECEDENCE - 2) public class PropsPropertyResolver implements PropertyValueResolver { @Override public boolean supports(Field field) { return field.isAnnotationPresent(Props.class); } }
@Value
支持EL表达式@Props
一样同样支持构造器,Field注入#{key}
和Environment#getProperty(String key, Class targetType)效果一样${1+1}
支持EL表达式@Configuration public class WebMvc implements WebMvcConfiguration { private final String serverPath; @Autowired public WebMvc(@Value("#{site.serverPath}") String serverPath) { this.serverPath = serverPath; } @Override public void configureResourceMappings(ResourceMappingRegistry registry) { registry.addResourceMapping("/assets/**")// // .enableGzip()// // .gzipMinLength(10240)// // G:\Projects\Git\today-technology\blog .addLocations("file:///G:/Projects/Git/today-technology/blog/blog-web/src/main/webapp/assets/"); registry.addResourceMapping("/webjars/**")// .addLocations("classpath:/META-INF/resources/webjars/"); registry.addResourceMapping("/swagger/**")// .cacheControl(CacheControl.newInstance().publicCache())// .addLocations("classpath:/META-INF/resources/"); registry.addResourceMapping("/upload/**")// .addLocations("file:///" + serverPath + "/upload/"); registry.addResourceMapping("/favicon.ico")// .addLocations("classpath:/favicon.ico")// .cacheControl(CacheControl.newInstance().publicCache()); registry.addResourceMapping(AdminInterceptor.class)// .setPathPatterns("/assets/admin/**")// .setOrder(Ordered.HIGHEST_PRECEDENCE)// .addLocations("file:///G:/Projects/Git/today-technology/blog/blog-web/src/main/webapp/assets/admin/"); } }
@Configuration
注解该注解标识一个配置Bean,示例:
@Configuration @Props(prefix = { "redis.pool.", "redis." }) public class RedisConfiguration { private int maxIdle; private int minIdle; private int timeout; private int maxTotal; private int database; private String address; private String password; private String clientName; private int connectTimeout; @Singleton("fstCodec") public Codec codec() { return new FstCodec(); } // @Singleton("limitLock") // public Lock limitLock(Redisson redisson) { // return redisson.getLock("limitLock"); // } @Singleton(destroyMethods = "shutdown") public Redisson redisson(@Autowired("fstCodec") Codec codec) { Config config = new Config(); config.setCodec(codec)// .useSingleServer()// .setAddress(address)// .setTimeout(timeout)// .setPassword(password)// .setDatabase(database)// .setClientName(clientName)// .setConnectionPoolSize(maxTotal)// .setConnectTimeout(connectTimeout)// .setConnectionMinimumIdleSize(minIdle)// .setConnectionMinimumIdleSize(maxIdle); return (Redisson) Redisson.create(config); } @Singleton("loggerDetails") public <T> Queue<T> loggerDetails(Redisson redisson) { return new ConcurrentLinkedQueue<T>(); } @Singleton("cacheViews") public Map<Long, Long> cacheViews(Redisson redisson) { return redisson.getMap("cacheViews", LongCodec.INSTANCE); } @Singleton("articleLabels") public Map<Long, Set<Label>> articleLabels(Redisson redisson, @Autowired("fstCodec") Codec codec) { return redisson.getMap("articleLabels", codec); } @Singleton("optionsMap") public Map<String, String> optionsMap(Redisson redisson) { // redisson.getKeys().flushdb(); return redisson.getMap("optionsMap", StringCodec.INSTANCE); } @Singleton("categories") public List<Category> categories(Redisson redisson, @Autowired("fstCodec") Codec codec) { return redisson.getList("categories", codec); } @Singleton("labels") public Set<Label> labels(Redisson redisson, @Autowired("fstCodec") Codec codec) { return redisson.getSet("labels", codec); } @Value(value = "#{limit.time.out}", required = false) private int limitTimeOut = Constant.ACCESS_TIME_OUT; @Singleton("limitCache") public Map<String, Long> limitCache(Redisson redisson) { final RMapCache<String, Long> mapCache = redisson.getMapCache("limitCache", LongCodec.INSTANCE); mapCache.expire(limitTimeOut, TimeUnit.MILLISECONDS); return mapCache; } }
package test.context; import java.util.HashSet; import java.util.Map; import java.util.Set; import javax.annotation.PostConstruct; import javax.annotation.PreDestroy; import org.junit.Test; import cn.taketoday.context.ApplicationContext; import cn.taketoday.context.StandardApplicationContext; import cn.taketoday.context.annotation.Singleton; import cn.taketoday.context.bean.BeanDefinition; import cn.taketoday.context.factory.DisposableBean; import cn.taketoday.context.factory.InitializingBean; import lombok.extern.slf4j.Slf4j; /** * @author TODAY <br> * 2019-07-25 22:44 */ @Slf4j @Singleton public class LifecycleBean // implements DisposableBean, BeanNameAware, InitializingBean, BeanFactoryAware, EnvironmentAware, ApplicationContextAware { @Override public void setBeanName(String name) { log.info("setBeanName: {}", name); } @Override public void setEnvironment(Environment environment) { log.info("setEnvironment: {}", environment); } @Override public void setBeanFactory(BeanFactory beanFactory) { log.info("setBeanFactory: {}", beanFactory); } @Override public void setApplicationContext(ApplicationContext applicationContext) { log.info("setApplicationContext: {}", applicationContext); } @PostConstruct public void initData() { log.info("@PostConstruct"); } @Override public void afterPropertiesSet() throws Exception { log.info("afterPropertiesSet"); } @PreDestroy public void preDestroy() { log.info("preDestroy"); } @Override public void destroy() throws Exception { log.info("destroy"); } @Test public void testLifecycle() { final Set<Class<?>> beans = new HashSet<>(); beans.add(LifecycleBean.class); ClassUtils.setClassCache(beans); try (final ApplicationContext applicationContext = new StandardApplicationContext("info.properties")) { applicationContext.loadContext(beans); Map<String, BeanDefinition> beanDefinitionsMap = applicationContext.getEnvironment().getBeanDefinitionRegistry().getBeanDefinitions(); System.out.println(beanDefinitionsMap); } } }
2019-07-25 23:14:37.712 INFO - [ main] c.t.context.AbstractApplicationContext 150 - Starting Application Context at [2019-07-25 23:14:37.707].
2019-07-25 23:14:37.751 INFO - [ main] c.t.context.env.StandardEnvironment 236 - Found Properties Resource: [file:/G:/Projects/Git/github/today-context/target/test-classes/info.properties]
2019-07-25 23:14:37.771 INFO - [ main] c.t.context.env.StandardEnvironment 129 - Active profiles: [test, dev]
2019-07-25 23:14:37.858 DEBUG - [ main] c.t.context.AbstractApplicationContext 325 - Loading Application Listeners.
2019-07-25 23:14:37.896 DEBUG - [ main] c.t.context.AbstractApplicationContext 480 - Publish event: [cn.taketoday.context.event.BeanDefinitionLoadingEvent]
2019-07-25 23:14:37.918 DEBUG - [ main] c.t.context.AbstractApplicationContext 480 - Publish event: [cn.taketoday.context.event.LoadingMissingBeanEvent]
2019-07-25 23:14:37.921 DEBUG - [ main] c.t.context.AbstractApplicationContext 480 - Publish event: [cn.taketoday.context.event.BeanDefinitionLoadedEvent]
2019-07-25 23:14:37.922 DEBUG - [ main] c.t.context.AbstractApplicationContext 480 - Publish event: [cn.taketoday.context.event.DependenciesHandledEvent]
2019-07-25 23:14:37.923 DEBUG - [ main] c.t.context.factory.AbstractBeanFactory 581 - Start loading BeanPostProcessor.
2019-07-25 23:14:37.926 DEBUG - [ main] c.t.context.AbstractApplicationContext 480 - Publish event: [cn.taketoday.context.event.ContextPreRefreshEvent]
2019-07-25 23:14:37.927 DEBUG - [ main] c.t.context.AbstractApplicationContext 480 - Publish event: [cn.taketoday.context.event.ContextRefreshEvent]
2019-07-25 23:14:37.928 DEBUG - [ main] c.t.context.factory.AbstractBeanFactory 1002 - Initialization of singleton objects.
2019-07-25 23:14:37.929 DEBUG - [ main] c.t.context.factory.AbstractBeanFactory 651 - Initializing bean named: [lifecycleBean].
2019-07-25 23:14:37.929 INFO - [ main] test.context.LifecycleBean 59 - setBeanName: lifecycleBean
2019-07-25 23:14:37.930 INFO - [ main] test.context.LifecycleBean 69 - setBeanFactory: cn.taketoday.context.factory.StandardBeanFactory@5ce81285
2019-07-25 23:14:37.930 INFO - [ main] test.context.LifecycleBean 74 - setApplicationContext: cn.taketoday.context.StandardApplicationContext@78c03f1f
2019-07-25 23:14:37.930 INFO - [ main] test.context.LifecycleBean 64 - setEnvironment: cn.taketoday.context.env.StandardEnvironment@5ec0a365
2019-07-25 23:14:37.931 INFO - [ main] test.context.LifecycleBean 79 - @PostConstruct
2019-07-25 23:14:37.931 INFO - [ main] test.context.LifecycleBean 84 - afterPropertiesSet
2019-07-25 23:14:37.931 DEBUG - [ main] c.t.context.factory.AbstractBeanFactory 511 - Singleton bean is being stored in the name of [lifecycleBean]
2019-07-25 23:14:37.932 DEBUG - [ main] c.t.context.factory.AbstractBeanFactory 1008 - The singleton objects are initialized.
2019-07-25 23:14:37.932 DEBUG - [ main] c.t.context.AbstractApplicationContext 480 - Publish event: [cn.taketoday.context.event.ContextStartedEvent]
2019-07-25 23:14:37.941 INFO - [ main] c.t.context.AbstractApplicationContext 210 - Application Context Startup in 234ms
{lifecycleBean={
"name":"lifecycleBean",
"scope":"SINGLETON",
"beanClass":"class test.context.LifecycleBean",
"initMethods":"[public void test.context.LifecycleBean.initData()]",
"destroyMethods":"[]",
"propertyValues":"[]",
"initialized":"true",
"factoryBean":"false",
"abstract":"false"
}}
2019-07-25 23:14:37.943 DEBUG - [ main] c.t.context.AbstractApplicationContext 480 - Publish event: [cn.taketoday.context.event.ContextCloseEvent]
context is closing
2019-07-25 23:14:37.945 INFO - [ main] c.t.c.listener.ContextCloseListener 52 - Closing: [cn.taketoday.context.StandardApplicationContext@78c03f1f] at [2019-07-25 23:14:37.943]
2019-07-25 23:14:37.947 INFO - [ main] test.context.LifecycleBean 89 - preDestroy
2019-07-25 23:14:37.947 INFO - [ main] test.context.LifecycleBean 94 - destroy
原文转自:https://www.cnblogs.com/zhaoweihang/p/9698852.html <field name="partner_id" string="Customer" widget="res_partner_many2one" context="{'default_name': contact_name, 'default_street': street, '
聚宽的API文档对Portfolio,Context对象的描述理解不清晰,自己动手输出了Portfolio,Context对象的详细属性。(遇到不理解不明白的地方,自己动手实践输出) Portfolio对象 Portfolio({ 'available_cash': 26581.98, 'subportfolios': [SubPortfolio({'available_cash': 26581.
<field name="partner_id" string="Customer" widget="res_partner_many2one" context="{'default_name': contact_name, 'default_street': street, 'default_city': city, 'default_state_id': state_id, 'default_
<context:annotation-config>与<context:component-scan>的区别 声明:本文转自stackoverflow;讲解十分详细,十分精彩,特此分享到CSDN;有时间的话,我会翻译一下,BUT,NOT TODAY; Ref:Difference between <context:annotation-config> vs <context:component-
The approaches in this post are now obsolete thanks to Go 1.7, which adds the context package to the standard library and uses it in the *net/http http.Request type. The background info here may still
title: "React v16.6.0: lazy, memo and contextType" author: [sebmarkbage] Today we're releasing React 16.6 with a few new convenient features. A form of PureComponent/shouldComponentUpdate for function
写在首行:开发语言为JAVA 按照郭神的教程集成百度SDK之后运行失败,参考了百度官网的集成说明,发现需要做地图的初始化,引用自:androidsdk | 百度地图API SDK 第三步:地图初始化 注意:在SDK各功能组件使用之前都需要调用“SDKInitializer.initialize(getApplicationContext())”,因此建议在应用创建时初始化SDK引用的Context
1.修改datepicker 中 today 按钮默认选中今天: 在jquery-ui.js中找到_attachHandlers _attachHandlers: function(e) { var i = this._get(e, "stepMonths"), s = "#" + e.id.replace(/\\\\/g, "\\"),
今天遇到一个问题 ,在Fragment中使用Recyclerview设置空布局的时候, View view = LayoutInflater.from(getContext()).inflate(R.layout.item_today_plan_container, null); 出现如上问题: java.lang.NullPointerException: Attempt to invoke v
在不讨论原因的情况下,假设有人想要一个老式的Play Framework web服务,并且不想使用依赖注入,也不想依赖Google的Guice。在玩法2.8.x中还可能吗? 有没有一个简单的方法可以让你不去这里就呆在老学校里? 我承认,但不完全理解https://www.playframework.com/documentation/2.4.x/migration24。我认为我的问题与2.7中删除
在React中,想做依赖注入(Dependency Injection)其实相当简单。请看下面这个例子: // Title.jsx export default function Title(props) { return <h1>{ props.title }</h1>; } // Header.jsx import Title from './Title.jsx'; export defa
依赖注入 Dependency Injection is a strong mechanism, which helps us easily manage dependencies of our classes. It is very popular pattern in strongly typed languages like C# and Java. 依赖注入是一个很强大的机制,该机制可以帮
简介 Hyperf 默认采用 hyperf/di 作为框架的依赖注入管理容器,尽管从设计上我们允许您更换其它的依赖注入管理容器,但我们强烈不建议您更换该组件。 hyperf/di 是一个强大的用于管理类的依赖关系并完成自动注入的组件,与传统依赖注入容器的区别在于更符合长生命周期的应用使用、提供了 注解及注解注入 的支持、提供了无比强大的 AOP 面向切面编程 能力,这些能力及易用性作为 Hyper
出自维基百科 Wikipedia: 依赖注入是一种允许我们从硬编码的依赖中解耦出来,从而在运行时或者编译时能够修改的软件设计模式。 这句解释让依赖注入的概念听起来比它实际要复杂很多。依赖注入通过构造注入,函数调用或者属性的设置来提供组件的依赖关系。就是这么简单。
问题内容: 根据我的经验,Maven在小型/实验性应用程序中常常是过大的。但是,依赖管理是Maven的一项非常有用的功能,实际上是唯一对上述应用程序类型真正有用的功能。 我想知道是否可以有一个 非常最小的轻量级 Eclipse-Maven集成,该集成 仅以 最简单的方式 仅 将Maven依赖项添加到Eclipse项目类路径中。 特别是我不想: 适用于任何Maven约定(包括项目布局召集人) 安装并
问题内容: 我想知道 _什么是Spring Framework? 为什么和何时应该在Java Enterprise开发中使用它? _ 答案将是“依赖注入框架”。好了,使用依赖注入框架时我们有什么优势?用setter值和/或构造函数参数描述类的想法对我来说似乎很奇怪。为什么这样 因为我们可以更改属性而无需重新编译项目?这就是我们所获得的一切吗? 那么,我们应该用什么对象来描述?所有对象还是只有几个?