Announcement Announcement Module
Collapse
No announcement yet.
real basic understanding problem with DI .... Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • real basic understanding problem with DI ....

    i'm trying to get started with spring DI and running into a problem where DI doesnt appear to happend and i dont understand why



    so i have a @Configuration class to generate two beans like this


    @Configuration
    class SecondarySpringInstrumentConfig {

    @Bean Guitar electric () { Guitar instrument = new Guitar ()
    instrument.noise = "pding pding "
    println instrument.toString () + " generating electric bean - plays " + instrument.noise
    return instrument
    }

    @Bean Player sally () { def player = new Player ()
    player.hereIsYourInstrument(electric())
    println player.toString() + " new sally bean built with "+ player.instrument.toString () + " and plays " + player.instrument.noise
    return player
    }

    }


    this all works ok .

    so i have a simple main app that loads the context - so i defined the electric bean above - and i try do a DI
    injection into class MainApp - tried @Named, and @resource cant either to work. When i create an instance of MainApp i expected the Guitar g attribute to be filled via DI - its actually null

    i can look up the bean - thats what leccy points to - thats fine - and the bean is returned -

    but the DI above does not.

    What am i doing wrong ?




    import javax.annotation.Resource

    import org.springframework.context.annotation.AnnotationC onfigApplicationContext

    class MainApp {

    //@Value ("#{electric}") Guitar g //inject
    //@Named ("electric") Guitar g //inject
    @Resource (name="electric") Guitar g //inject

    static void main (args)
    {
    //ApplicationContext ctx = new ClassPathXmlApplicationContext ("org/spring/application-context.xml")
    AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext (/*SpringInstrumentConfig.class*/)
    ctx.register (SpringInstrumentConfig.class) //add extra config item later
    ctx.register (SecondarySpringInstrumentConfig.class) //add extra config item later
    ctx.refresh()
    Player performer = ctx.getBean("duke")

    performer.showTime()

    performer = ctx.getBean("sally")
    println performer.toString() + " sally + with instrument " + performer.instrument
    performer.showTime()

    Instrument leccy = ctx.getBean("electric")
    print leccy.toString() + " electric guitar leccy with noise " + leccy.noise + " : " ; leccy.play()

    def app = new MainApp() //expected this to trigger the DI on Guitar g - get null
    app.func()
    app.func2(leccy)

    }


    def func ()
    {
    println "guitar g plays " + g?.play()
    }

    def func2 (Instrument g)
    {
    print "guitar plays " + g.play()
    }
    }

  • #2
    Please use [ code][/code ] tags to post code/xml/stacktraces that way they remain readable ...

    Why should a bean/class not known to the applicationcontext be automatically injected? So no creating a bean of class not known to the container will NOT trigger dependency injection. Even creation of a class known to the context will not trigger dependency injection as you would need to get the bean from the context instead of creating a new instance yourself.

    There is a way and that involves AOP and AspectJ (that is explained in the reference guide).

    Comment


    • #3
      so i think i kind of found something similar over th weekend doing random google searches and ended up with this little area in AOP

      i've read the bible (3.2.2. user guide) and tried what it said and it still doesnt work - so i must still be doing it wrong

      heres what i have

      1. my project dependeicnes includes the spring-aspects.jar - done

      2. i've annotated a class as @Configurable like this - but its not directly a bean itself - but does set up the expectation for DI using the @resource annotation like this

      Code:
      @Configurable (value="musicPlayer", dependencyCheck=true)
      class MusicPlayer {
      	
      	@Resource(name="electric")
      	Guitar electric
      	
      	void startPlay()
      	{
      		print "mp starting to play - playing instrument : " 
      		electric.play()
      	}
      	 
      
      }
      3. the documentation says that what your doing is essentially triggering a bean construction template on an object you create when you call def xyz = new MusicPlayer(). In order for that i have to have a bean recipe known in the container. so i added bean defn in my @Configuration class for it - and enabled the @EnableSpringConfigured on my tope level config class lie this.

      Code:
      @Configuration
      @EnableSpringConfigured	//turn on to enable DI on @Configurable items outside contrainer 
      class SecondarySpringInstrumentConfig {
      	
      	@Bean Guitar electric () { Guitar instrument = new Guitar ()
      			instrument.noise = "pding pding "
      		println instrument.toString () + " generating electric bean - plays " + instrument.noise
      			return instrument
      	}
      	
      	@Bean Player sally () { def player =  new Player ()
      		player.hereIsYourInstrument(electric())
      		println player.toString() + " new sally bean built with  "+ player.instrument.toString () + " and plays " + player.instrument.noise
      		return player
      	}
      	
      	@Bean @Scope ("prototype") 	
                    MusicPlayer musicPlayer () {println "called musicPlayer bean recipe"
      		return new MusicPlayer()
      	}
      	
      }
      i made the scope prototype because i'm going to be calling new on the MusicPlayer.

      all compiles - no problem - i'm using groovy rather java if your wondering where all the semicolons are going

      4. run this with the following in my mainapp

      Code:
      class MainApp {
      	@Resource (name="electric") Guitar g	//inject
      	
      	static void main (args)
      	{
      		//ApplicationContext ctx = new ClassPathXmlApplicationContext ("org/spring/application-context.xml")
      		AnnotationConfigApplicationContext ctx = new AnnotationConfigApplicationContext (/*SpringInstrumentConfig.class*/)
      		ctx.register (SpringInstrumentConfig.class)  //add extra config item later
      		ctx.register (SecondarySpringInstrumentConfig.class)  //add extra config item later
      		ctx.refresh()
      		Player performer  = ctx.getBean("duke")
      		
      		performer.showTime()
      		
      		performer = ctx.getBean("sally")
      		println performer.toString() + " sally  +  with instrument " + performer.instrument 
      		performer.showTime()
      		
      		Instrument leccy = ctx.getBean("electric")
      		print leccy.toString()  + " electric guitar leccy with noise " + leccy.noise + " : " ;  leccy.play()
      		
      		def mp = new MusicPlayer()  //hopefully trigger the AOP behaviour - but doesnt 
      		mp.startPlay()  //null pointer error on the DI resource
      so finally what am i doing wrong/missing - also to get all the log output thats not showing what the container is not doing - how do i turn that on - so that i can see in the console what its ignoring

      it would be good to try and knock this one of 'silly me' dont do that in future behaviours and know how to successfuly do it when i need to. Im sure others must fall foul of this when they are trying to start from scratch with simple examples

      Yours in advance

      Comment


      • #4
        as this didnt do anything seems i'm missing something else in i might need to pass to the vm. various searches say you have to pass -javaagent:lib/...spring-agent.jar to the runtime launch.

        so i updated my gradle dependencies like this

        Code:
        	"org.springframework:spring-instrument:${springVersion}",
            "org.springframework:spring-agent:2.5.6.SEC03",
        which downs these to the gradle cache and adds to my project library list

        i try to pass the vm argument in the luancher config like this

        -javaagent:lib/org.springframework/spring-agent/2.5.6.SEC03/jar

        which is the path in the gradle cache - and i get an error like this

        Code:
        Error occurred during initialization of VM
        agent library failed to init: instrument
        Error opening zip file or JAR manifest missing : lib/org.springframework/spring-agent/2.5.6.SEC03/jar
        it doesnt matter how i put the reference in tried without org.xx path and just tried spring-agent, spring-agent-2.5.6.SEC03, etc essentially the vm launch says it cant open the path to the jar and stops dead.

        GRRHSHHS - this is so kind of frustrating - has any one else managed to do this with basic compile time weaving and can share what their launch config looks like in eclipse. its enough to drive anyone to drink

        still not sure if that would make it work but i'd like to know

        Comment


        • #5
          brute force doesnt seem to work - in desperation - i created a /lib in my project. I copied the spring-agent-2.5.6.jar from the cache stuck in that strange zip file gradle generates for you into the /lib directory.

          to keep it simple i renamed it to lib/spring-agent.jar. I then updated the launcher and pointed as
          -javaaegent:lib/spring-agent.jar, and then tried to run the main app again - this time it runs (clearly found the jar i just put there) but i still get no DI from spring so back to square 1

          i've just read the docs again - and it says spring-instrument replaces spring-agent - so i'ce dropped the spring-agent and just copied the spring-instrument jar into that /lib directory and changed the launcher to -javaagent:lib/spring-instrument.jar. Still does not work.

          I tried to adding load time weaving like this
          Code:
          @Configuration
          @EnableSpringConfigured	//turn on to enable DI on @Configurable items outside contrainer 
          @EnableLoadTimeWeaving
          absolutely no difference and DI isnt triggered on the new MusicPlayer()

          has any one ever got this blasted DI into @Configurable class to work ? as well as how you tell the launcher to include a jar within the gradle ivy cache - so that it can see the jar, i just cant seem to ge the path name right.

          Will
          Last edited by will.woodman; Apr 15th, 2013, 05:09 PM.

          Comment

          Working...
          X